@ziggs-ai/ziggs-mcp 0.9.1 → 0.9.2
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/toolError.d.ts +10 -10
- package/dist/toolError.js +45 -53
- package/package.json +2 -2
package/dist/toolError.d.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ZIG-667 — one error surface for every MCP tool.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* LLM callers stall on stack-trace prose; they recover from errors they can
|
|
8
|
-
* parse. This module strips the internals, keeps a stable machine-readable
|
|
9
|
-
* code, and for authorization denials says what to do next.
|
|
4
|
+
* ZIG-1124 — classify from the thrown {@link ApiError} fields (`status`,
|
|
5
|
+
* `code`, `body` / `message`). No client-prefix strip, no HTTP-status regex,
|
|
6
|
+
* no re-parsing a JSON body that was concatenated into the message string.
|
|
10
7
|
*/
|
|
11
8
|
export interface ToolErrorShape {
|
|
12
9
|
code: string;
|
|
13
10
|
message: string;
|
|
14
11
|
hint?: string;
|
|
15
12
|
}
|
|
16
|
-
/**
|
|
17
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Classify a thrown client error (or a plain string this layer raised) into a
|
|
15
|
+
* stable MCP shape.
|
|
16
|
+
*/
|
|
17
|
+
export declare function classifyToolError(input: unknown): ToolErrorShape;
|
|
18
18
|
/**
|
|
19
19
|
* MCP tool error result: machine-readable code + cleaned message (+ hint).
|
|
20
20
|
*
|
|
21
21
|
* Pass the caught error itself, not `err.message` — an `ApiError` carries the
|
|
22
|
-
* HTTP status
|
|
23
|
-
* still accepted for refusals this layer raises on its own.
|
|
22
|
+
* HTTP status and server `code` that decide the hint (ZIG-1086 / ZIG-1124).
|
|
23
|
+
* A plain string is still accepted for refusals this layer raises on its own.
|
|
24
24
|
*/
|
|
25
25
|
export declare function toolError(input: unknown): {
|
|
26
26
|
content: {
|
package/dist/toolError.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ZIG-667 — one error surface for every MCP tool.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* LLM callers stall on stack-trace prose; they recover from errors they can
|
|
8
|
-
* parse. This module strips the internals, keeps a stable machine-readable
|
|
9
|
-
* code, and for authorization denials says what to do next.
|
|
4
|
+
* ZIG-1124 — classify from the thrown {@link ApiError} fields (`status`,
|
|
5
|
+
* `code`, `body` / `message`). No client-prefix strip, no HTTP-status regex,
|
|
6
|
+
* no re-parsing a JSON body that was concatenated into the message string.
|
|
10
7
|
*/
|
|
11
|
-
const CLIENT_PREFIX = /^[A-Z][A-Za-z0-9]*Client\.[A-Za-z0-9_]+\s+/;
|
|
12
|
-
const HTTP_STATUS = /(?:^|\s)([1-5]\d{2})(?=\s|$)/;
|
|
13
8
|
const SCOPE_DENIED_HINT = 'You are not authorized for this scope. To get access: ask the counterparty ' +
|
|
14
9
|
'to issue you a context grant (they run ziggs_context_issue_grant), or propose a ' +
|
|
15
10
|
'bilateral link first (ziggs_agreement_propose with engagementKind "link"). Check what you can already ' +
|
|
@@ -39,51 +34,52 @@ function codeForStatus(status) {
|
|
|
39
34
|
return 'BAD_REQUEST';
|
|
40
35
|
return 'TOOL_ERROR';
|
|
41
36
|
}
|
|
42
|
-
/** Pull a human reason out of an embedded backend JSON body, if any. */
|
|
43
|
-
function extractBodyReason(raw) {
|
|
44
|
-
const start = raw.indexOf('{');
|
|
45
|
-
if (start === -1)
|
|
46
|
-
return null;
|
|
47
|
-
try {
|
|
48
|
-
const parsed = JSON.parse(raw.slice(start));
|
|
49
|
-
const reason = parsed['error'] ?? parsed['message'];
|
|
50
|
-
return typeof reason === 'string' && reason.trim() ? reason.trim() : null;
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
37
|
/**
|
|
57
38
|
* An `ApiError` from api-client, recognised by shape rather than `instanceof`:
|
|
58
39
|
* a bundled or duplicated copy of the class would fail an identity check while
|
|
59
40
|
* carrying exactly the fields we need.
|
|
60
41
|
*/
|
|
61
|
-
function
|
|
62
|
-
if (typeof err
|
|
63
|
-
return null;
|
|
64
|
-
|
|
65
|
-
|
|
42
|
+
function thrownFields(err) {
|
|
43
|
+
if (typeof err === 'string') {
|
|
44
|
+
return { message: err, status: null, code: null };
|
|
45
|
+
}
|
|
46
|
+
if (typeof err !== 'object' || err === null) {
|
|
47
|
+
return { message: String(err), status: null, code: null };
|
|
48
|
+
}
|
|
49
|
+
const o = err;
|
|
50
|
+
const status = typeof o.status === 'number' && o.status >= 100 && o.status < 600
|
|
51
|
+
? o.status
|
|
52
|
+
: null;
|
|
53
|
+
const code = typeof o.code === 'string' && o.code ? o.code : null;
|
|
54
|
+
const message = typeof o.message === 'string' && o.message ? o.message : String(err);
|
|
55
|
+
return { message, status, code };
|
|
66
56
|
}
|
|
67
|
-
/**
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Classify a thrown client error (or a plain string this layer raised) into a
|
|
59
|
+
* stable MCP shape.
|
|
60
|
+
*/
|
|
61
|
+
export function classifyToolError(input) {
|
|
62
|
+
const { message, status, code: machineCode } = thrownFields(input);
|
|
63
|
+
if (machineCode === 'AGENT_LACKS_HUMAN_AUTHORITY') {
|
|
64
|
+
return {
|
|
65
|
+
code: 'AGENT_LACKS_HUMAN_AUTHORITY',
|
|
66
|
+
message,
|
|
67
|
+
hint: HUMAN_AUTHORITY_HINT,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (machineCode === 'NOT_AUTHORIZED_FOR_SCOPE') {
|
|
71
|
+
return {
|
|
72
|
+
code: 'NOT_AUTHORIZED_FOR_SCOPE',
|
|
73
|
+
message,
|
|
74
|
+
hint: SCOPE_DENIED_HINT,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
78
77
|
if (status === null) {
|
|
79
|
-
return { code: 'TOOL_ERROR', message
|
|
78
|
+
return { code: 'TOOL_ERROR', message };
|
|
80
79
|
}
|
|
81
80
|
const code = codeForStatus(status);
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
// The human-authority guard refuses every impersonated agent, whatever it
|
|
85
|
-
// asked for. Checked before the scope branch below: its message also mentions
|
|
86
|
-
// scopes, and "ask for a grant on this scope" is the wrong advice here.
|
|
81
|
+
// Backend human-authority already sends AGENT_LACKS_HUMAN_AUTHORITY; keep a
|
|
82
|
+
// message fallback for older bodies / tests that omit `code`.
|
|
87
83
|
if (code === 'NOT_AUTHORIZED' && /impersonated agent cannot perform/i.test(message)) {
|
|
88
84
|
return {
|
|
89
85
|
code: 'AGENT_LACKS_HUMAN_AUTHORITY',
|
|
@@ -91,9 +87,8 @@ export function classifyToolError(rawMessage, knownStatus) {
|
|
|
91
87
|
hint: HUMAN_AUTHORITY_HINT,
|
|
92
88
|
};
|
|
93
89
|
}
|
|
94
|
-
//
|
|
95
|
-
// code
|
|
96
|
-
// keep the generic code — their fixes live in other domains.
|
|
90
|
+
// Many scope denials still throw a bare ForbiddenException string with no
|
|
91
|
+
// machine code — classify those by the word "scope" in the message.
|
|
97
92
|
if (code === 'NOT_AUTHORIZED' && /\bscope\b/i.test(message)) {
|
|
98
93
|
return {
|
|
99
94
|
code: 'NOT_AUTHORIZED_FOR_SCOPE',
|
|
@@ -107,14 +102,11 @@ export function classifyToolError(rawMessage, knownStatus) {
|
|
|
107
102
|
* MCP tool error result: machine-readable code + cleaned message (+ hint).
|
|
108
103
|
*
|
|
109
104
|
* Pass the caught error itself, not `err.message` — an `ApiError` carries the
|
|
110
|
-
* HTTP status
|
|
111
|
-
* still accepted for refusals this layer raises on its own.
|
|
105
|
+
* HTTP status and server `code` that decide the hint (ZIG-1086 / ZIG-1124).
|
|
106
|
+
* A plain string is still accepted for refusals this layer raises on its own.
|
|
112
107
|
*/
|
|
113
108
|
export function toolError(input) {
|
|
114
|
-
const
|
|
115
|
-
? input
|
|
116
|
-
: (input?.message ?? String(input));
|
|
117
|
-
const shape = classifyToolError(String(message), thrownStatus(input));
|
|
109
|
+
const shape = classifyToolError(input);
|
|
118
110
|
return {
|
|
119
111
|
content: [
|
|
120
112
|
{ type: 'text', text: JSON.stringify({ error: shape }, null, 2) },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/ziggs-mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "MCP server for Claude Code, Cursor, and other MCP hosts \u2014 act as your Ziggs delegate agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
39
|
-
"@ziggs-ai/api-client": "^0.9.
|
|
39
|
+
"@ziggs-ai/api-client": "^0.9.1",
|
|
40
40
|
"dotenv": "^16.6.1",
|
|
41
41
|
"zod": "^3.24.2"
|
|
42
42
|
},
|