@ziggs-ai/ziggs-mcp 0.23.1 → 0.24.0
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/dist/server.js +2 -1
- package/dist/surface.d.ts +8 -1
- package/dist/surface.js +34 -24
- package/dist/toolPick.d.ts +27 -0
- package/dist/toolPick.js +39 -0
- package/dist/tools.js +4 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -6,6 +6,7 @@ import { loadConfig } from './config.js';
|
|
|
6
6
|
import { credsFromConfig } from './creds.js';
|
|
7
7
|
import { registerZiggsTools } from './tools.js';
|
|
8
8
|
import { applySurfacePolicy } from './surface.js';
|
|
9
|
+
import { backendToolPick } from './toolPick.js';
|
|
9
10
|
import { renderInstructions } from './protocol/delegateProtocol.js';
|
|
10
11
|
const require = createRequire(import.meta.url);
|
|
11
12
|
const { version } = require('../package.json');
|
|
@@ -25,7 +26,7 @@ export function createZiggsMcpServer(creds, cfg) {
|
|
|
25
26
|
registerZiggsTools(server, creds, cfg);
|
|
26
27
|
// Decide what a caller loads natively and what it reaches through
|
|
27
28
|
// the catalog. Runs after registration because the catalog is built by it.
|
|
28
|
-
applySurfacePolicy(server);
|
|
29
|
+
applySurfacePolicy(server, { pickTool: backendToolPick(creds) });
|
|
29
30
|
return server;
|
|
30
31
|
}
|
|
31
32
|
/** Drop this process's inbox host. Best-effort — shutdown must not fail on it. */
|
package/dist/surface.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type PickTool } from './toolPick.js';
|
|
2
3
|
import { type CatalogEntry } from './toolCatalog.js';
|
|
3
4
|
/**
|
|
4
5
|
* The tools a cold session gets natively, with their full schemas.
|
|
@@ -23,6 +24,9 @@ import { type CatalogEntry } from './toolCatalog.js';
|
|
|
23
24
|
* Deliberately NOT native: the agreement verbs, payments, artifacts, grants,
|
|
24
25
|
* links, connections, tasks beyond the result. Every one of them is a real
|
|
25
26
|
* capability an agent reaches for occasionally and pays for constantly.
|
|
27
|
+
*
|
|
28
|
+
* The names live in api-client (`EVERYDAY_MCP_TOOLS`) so the hosted brain
|
|
29
|
+
* loads the same set and the two doors cannot drift.
|
|
26
30
|
*/
|
|
27
31
|
export declare const NATIVE_TOOLS: readonly string[];
|
|
28
32
|
/**
|
|
@@ -80,4 +84,7 @@ export declare function callLine(entry: CatalogEntry): string;
|
|
|
80
84
|
* hand-building that response would risk a schema-shape difference on exactly
|
|
81
85
|
* the tools every caller loads. We filter its output and change nothing else.
|
|
82
86
|
*/
|
|
83
|
-
export declare function applySurfacePolicy(server: McpServer
|
|
87
|
+
export declare function applySurfacePolicy(server: McpServer, opts?: {
|
|
88
|
+
/** Answers `ziggs_tools need=`. Absent: `need` falls back to the full list. */
|
|
89
|
+
pickTool?: PickTool;
|
|
90
|
+
}): void;
|
package/dist/surface.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
import { EVERYDAY_DESTRUCTIVE_MCP, EVERYDAY_MCP_TOOLS } from '@ziggs-ai/api-client';
|
|
3
4
|
import { readOnly, write } from './toolAnnotations.js';
|
|
4
5
|
import { registerStrictTool } from './strictParams.js';
|
|
5
6
|
import { toolError } from './toolError.js';
|
|
6
7
|
import { textResult } from './capabilityAdapter.js';
|
|
7
8
|
import { aliasMatches } from './toolAliases.js';
|
|
9
|
+
import { pickLine } from './toolPick.js';
|
|
8
10
|
import { catalogEntry, catalogFor, catalogRow, describeEntry, removeCatalogEntry, } from './toolCatalog.js';
|
|
9
11
|
/**
|
|
10
12
|
* The tools a cold session gets natively, with their full schemas.
|
|
@@ -29,25 +31,11 @@ import { catalogEntry, catalogFor, catalogRow, describeEntry, removeCatalogEntry
|
|
|
29
31
|
* Deliberately NOT native: the agreement verbs, payments, artifacts, grants,
|
|
30
32
|
* links, connections, tasks beyond the result. Every one of them is a real
|
|
31
33
|
* capability an agent reaches for occasionally and pays for constantly.
|
|
34
|
+
*
|
|
35
|
+
* The names live in api-client (`EVERYDAY_MCP_TOOLS`) so the hosted brain
|
|
36
|
+
* loads the same set and the two doors cannot drift.
|
|
32
37
|
*/
|
|
33
|
-
export const NATIVE_TOOLS =
|
|
34
|
-
'ziggs_inbox',
|
|
35
|
-
// Count-only orientation: who you are and whether mail is waiting, without
|
|
36
|
-
// taking the mailbox. The full read below is the one that acquires.
|
|
37
|
-
'ziggs_inbox_peek',
|
|
38
|
-
// The ack is native beside the read it follows: a readPlan ends with it, and
|
|
39
|
-
// a caller that had to go through the catalog to close its loop would pay the
|
|
40
|
-
// dispatcher on every pass.
|
|
41
|
-
'ziggs_inbox_ack',
|
|
42
|
-
'ziggs_open',
|
|
43
|
-
'ziggs_context_read',
|
|
44
|
-
'ziggs_chat_open',
|
|
45
|
-
'ziggs_chat_send',
|
|
46
|
-
'ziggs_task_set_result',
|
|
47
|
-
// And every irreversible tool — see DESTRUCTIVE_STAY_NATIVE below.
|
|
48
|
-
'ziggs_agreement_revoke',
|
|
49
|
-
'ziggs_context_revoke_grant',
|
|
50
|
-
];
|
|
38
|
+
export const NATIVE_TOOLS = EVERYDAY_MCP_TOOLS;
|
|
51
39
|
/**
|
|
52
40
|
* Irreversible tools stay natively listed, and the write dispatcher refuses
|
|
53
41
|
* them.
|
|
@@ -68,10 +56,7 @@ export const NATIVE_TOOLS = [
|
|
|
68
56
|
* If a third destructive tool ever appears, it belongs in both lists. The test
|
|
69
57
|
* in `core-only-tier.test.ts` fails if one is added and not listed here.
|
|
70
58
|
*/
|
|
71
|
-
export const DESTRUCTIVE_STAY_NATIVE =
|
|
72
|
-
'ziggs_agreement_revoke',
|
|
73
|
-
'ziggs_context_revoke_grant',
|
|
74
|
-
];
|
|
59
|
+
export const DESTRUCTIVE_STAY_NATIVE = EVERYDAY_DESTRUCTIVE_MCP;
|
|
75
60
|
const TOOLS_CATALOG_NAME = 'ziggs_tools';
|
|
76
61
|
const TOOL_READ_NAME = 'ziggs_tool_read';
|
|
77
62
|
const TOOL_WRITE_NAME = 'ziggs_tool_write';
|
|
@@ -100,6 +85,7 @@ const ZIGGS_API = 'the Ziggs API (https://api.ziggsai.com, reference at https://
|
|
|
100
85
|
const TOOLS_DESCRIPTION = 'Every Ziggs tool that exists: name plus one line, for the whole surface. ' +
|
|
101
86
|
'A handful of everyday tools are already loaded natively; the rest live here. Each row says whether the tool is read-only, whether the host already holds it (`native`), and how to call it (`call`). ' +
|
|
102
87
|
'Pass `describe` with one or more tool names to get their full descriptions, input schemas, and the same `call` line — do that before calling a tool you have not used in this session, so you pass the right arguments. ' +
|
|
88
|
+
'Pass `need` with a plain sentence of what you want done (e.g. "send a message to the customer", "cancel the task I am on") to get the one tool that does it, with its schema and call line, or "nothing fits" — when no single tool clearly fits you get the complete catalog instead. ' +
|
|
103
89
|
'Pass `search` to filter by name, title, or common intent (e.g. "contact", "permission", "grant", "artifact"). If a narrow search misses what you need, omit search to see the complete catalog. ' +
|
|
104
90
|
'Nothing is hidden: if a capability exists, its name is in this list.';
|
|
105
91
|
const TOOL_READ_DESCRIPTION = `Call a read-only Ziggs tool by name, against ${ZIGGS_API}. ` +
|
|
@@ -241,7 +227,7 @@ function registerDispatcher(server, lane) {
|
|
|
241
227
|
* hand-building that response would risk a schema-shape difference on exactly
|
|
242
228
|
* the tools every caller loads. We filter its output and change nothing else.
|
|
243
229
|
*/
|
|
244
|
-
export function applySurfacePolicy(server) {
|
|
230
|
+
export function applySurfacePolicy(server, opts = {}) {
|
|
245
231
|
const native = new Set(NATIVE_TOOLS);
|
|
246
232
|
listOnly(server, native);
|
|
247
233
|
registerStrictTool(server, TOOLS_CATALOG_NAME, TOOLS_DESCRIPTION, {
|
|
@@ -253,7 +239,11 @@ export function applySurfacePolicy(server) {
|
|
|
253
239
|
.string()
|
|
254
240
|
.optional()
|
|
255
241
|
.describe('Filter tools by name, title, or common intent such as contact, teammate, permission, or grant. Omit to list every tool.'),
|
|
256
|
-
|
|
242
|
+
need: z
|
|
243
|
+
.string()
|
|
244
|
+
.optional()
|
|
245
|
+
.describe('What you want done, in a plain sentence. Answers with the one tool that does it, or "nothing fits"; falls back to the full list when unsure.'),
|
|
246
|
+
}, readOnly('List every Ziggs tool'), async ({ describe, search, need }) => {
|
|
257
247
|
try {
|
|
258
248
|
if (describe?.length) {
|
|
259
249
|
// Sorted rows are the listing's business — a describe answers by name
|
|
@@ -278,6 +268,26 @@ export function applySurfacePolicy(server) {
|
|
|
278
268
|
});
|
|
279
269
|
}
|
|
280
270
|
const all = sortRows(catalogFor(server));
|
|
271
|
+
const wanted = need?.trim();
|
|
272
|
+
if (wanted && opts.pickTool && !search?.trim()) {
|
|
273
|
+
const answer = await opts.pickTool(wanted, all.map((e) => ({ name: e.name, line: pickLine(e.title, e.description) })));
|
|
274
|
+
const picked = answer?.how === 'pick' && answer.tool ? catalogEntry(server, answer.tool) : undefined;
|
|
275
|
+
if (picked) {
|
|
276
|
+
return textResult({
|
|
277
|
+
need: wanted,
|
|
278
|
+
tools: [withCall(picked, describeEntry(picked))],
|
|
279
|
+
next: `This is the one tool for that need. Call it as its call line says. If it is not what you meant, call ${TOOLS_CATALOG_NAME} with no arguments for every tool.`,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
if (answer?.how === 'nothing_fits') {
|
|
283
|
+
return textResult({
|
|
284
|
+
need: wanted,
|
|
285
|
+
tools: [],
|
|
286
|
+
nothingFits: `No Ziggs tool does this. Call ${TOOLS_CATALOG_NAME} with no arguments to check the full list yourself.`,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
// Unsure, off or unreachable: the list, exactly as without `need`.
|
|
290
|
+
}
|
|
281
291
|
const needle = search?.trim().toLowerCase();
|
|
282
292
|
const rows = (needle
|
|
283
293
|
? all.filter((e) => e.name.toLowerCase().includes(needle) ||
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type Creds } from '@ziggs-ai/api-client';
|
|
2
|
+
/** One catalog row as the picker reads it. */
|
|
3
|
+
export interface ToolPickOption {
|
|
4
|
+
name: string;
|
|
5
|
+
line: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* - `pick` one tool does the need: `tool` names it.
|
|
9
|
+
* - `nothing_fits` no tool does it.
|
|
10
|
+
* - `unsure` / `off` no answer worth giving: show the list.
|
|
11
|
+
*/
|
|
12
|
+
export interface ToolPickAnswer {
|
|
13
|
+
how: 'pick' | 'nothing_fits' | 'unsure' | 'off';
|
|
14
|
+
tool?: string;
|
|
15
|
+
confidence?: number;
|
|
16
|
+
}
|
|
17
|
+
/** Null means "no answer": the surface shows the list it always has. */
|
|
18
|
+
export type PickTool = (need: string, options: ToolPickOption[]) => Promise<ToolPickAnswer | null>;
|
|
19
|
+
/**
|
|
20
|
+
* The backend picker: `POST /internal/tool-pick` with this connection's key.
|
|
21
|
+
* The model call and its key live on the backend, since this server also runs
|
|
22
|
+
* on a caller's own machine. Any failure is null, including the 404 from a
|
|
23
|
+
* backend that predates the route.
|
|
24
|
+
*/
|
|
25
|
+
export declare function backendToolPick(creds: Creds): PickTool;
|
|
26
|
+
/** What the picker is told a tool does: its title and the first sentence it says. */
|
|
27
|
+
export declare function pickLine(title: string, description: string): string;
|
package/dist/toolPick.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { buildCredsHeaders, getBackendUrl } from '@ziggs-ai/api-client';
|
|
2
|
+
/** A listing is always the fallback, so waiting long for a pick buys nothing. */
|
|
3
|
+
const TIMEOUT_MS = 6000;
|
|
4
|
+
/**
|
|
5
|
+
* The backend picker: `POST /internal/tool-pick` with this connection's key.
|
|
6
|
+
* The model call and its key live on the backend, since this server also runs
|
|
7
|
+
* on a caller's own machine. Any failure is null, including the 404 from a
|
|
8
|
+
* backend that predates the route.
|
|
9
|
+
*/
|
|
10
|
+
export function backendToolPick(creds) {
|
|
11
|
+
return async (need, options) => {
|
|
12
|
+
if (!creds.operatorKey)
|
|
13
|
+
return null;
|
|
14
|
+
try {
|
|
15
|
+
const res = await fetch(`${getBackendUrl()}/internal/tool-pick`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: buildCredsHeaders(creds),
|
|
18
|
+
body: JSON.stringify({ need, options }),
|
|
19
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
20
|
+
});
|
|
21
|
+
if (!res.ok) {
|
|
22
|
+
await res.body?.cancel().catch(() => undefined);
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const data = (await res.json().catch(() => null));
|
|
26
|
+
if (!data || typeof data.how !== 'string')
|
|
27
|
+
return null;
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** What the picker is told a tool does: its title and the first sentence it says. */
|
|
36
|
+
export function pickLine(title, description) {
|
|
37
|
+
const first = description.split(/(?<=\.)\s/)[0] ?? '';
|
|
38
|
+
return `${title}. ${first}`.slice(0, 300);
|
|
39
|
+
}
|
package/dist/tools.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getAgreement, getMyAgreements, listMyChats, respondToAgreement, revokeAgreement, counterAgreement, fulfillAgreement, sendChatMessage, ConnectionsClient, PaymentsClient, ContextReadClient, GrantsClient, InboxClient, createTask, updateTaskState, acknowledgeTaskControl, replaceTaskPlan, updateTaskPlanSteps, listTasks, getTask, getBackendUrl, fetchMyOrgs, fetchSessionAccess, isMcpOAuthDelegateSession, GRANTS_CAPABILITIES, AGREEMENT_VERB_CAPABILITIES, CONTEXT_GRANT_SCOPE_KINDS, contextReadCapability, openCapability, accessExplainCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, recordArtifactCapability, listArtifactsCapability, findArtifactsCapability, shareArtifactCapability, attachArtifactCapability, uploadArtifactUrlCapability, completeArtifactFileCapability, downloadArtifactCapability, openConversationCapability, connectionProxyCapability, requestConnectionCapability, agreementClaimCapability, agreementSubcontractCapability, listTasksCapability, cancelTaskCapability, marketplaceViewCapability, parseListFields, pickListedRows, projectChatListRows, sessionOrientation, presentSendResult, presentTaskOutcome, } from '@ziggs-ai/api-client';
|
|
3
|
+
import { getAgreement, getMyAgreements, listMyChats, respondToAgreement, revokeAgreement, counterAgreement, fulfillAgreement, sendChatMessage, ConnectionsClient, PaymentsClient, ContextReadClient, GrantsClient, InboxClient, createTask, updateTaskState, acknowledgeTaskControl, replaceTaskPlan, updateTaskPlanSteps, listTasks, getTask, getBackendUrl, fetchMyOrgs, fetchSessionAccess, isMcpOAuthDelegateSession, GRANTS_CAPABILITIES, AGREEMENT_VERB_CAPABILITIES, LISTING_DOOR_CAPABILITIES, CONTEXT_GRANT_SCOPE_KINDS, contextReadCapability, openCapability, accessExplainCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, recordArtifactCapability, listArtifactsCapability, findArtifactsCapability, shareArtifactCapability, attachArtifactCapability, uploadArtifactUrlCapability, completeArtifactFileCapability, downloadArtifactCapability, openConversationCapability, connectionProxyCapability, requestConnectionCapability, agreementClaimCapability, agreementSubcontractCapability, listTasksCapability, cancelTaskCapability, marketplaceViewCapability, parseListFields, pickListedRows, projectChatListRows, sessionOrientation, presentSendResult, presentTaskOutcome, } from '@ziggs-ai/api-client';
|
|
4
4
|
import { decodeOperatorKeyClaims } from './operatorKey.js';
|
|
5
5
|
import { registerTrustTools } from './trustTools.js';
|
|
6
6
|
import { registerPaymentTools } from './paymentTools.js';
|
|
@@ -510,6 +510,9 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
510
510
|
registerCapabilities(server, AGREEMENT_VERB_CAPABILITIES, creds, {
|
|
511
511
|
webUrl: cfg.ZIGGS_WEB_URL,
|
|
512
512
|
});
|
|
513
|
+
// The publisher's own door on a listing it already holds: pause and resume.
|
|
514
|
+
// Apart from the verbs above because they form nothing.
|
|
515
|
+
registerCapabilities(server, LISTING_DOOR_CAPABILITIES, creds);
|
|
513
516
|
registerCapability(server, agreementClaimCapability, creds, {
|
|
514
517
|
webUrl: cfg.ZIGGS_WEB_URL,
|
|
515
518
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/ziggs-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
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": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
42
|
-
"@ziggs-ai/api-client": "0.
|
|
42
|
+
"@ziggs-ai/api-client": "0.24.0",
|
|
43
43
|
"dotenv": "^16.6.1",
|
|
44
44
|
"zod": "^3.24.2",
|
|
45
45
|
"zod-to-json-schema": "^3.25.1"
|