@bryan-thompson/inspector-assessment 1.36.3 → 1.36.4
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/cli/build/__tests__/jsonl-events.test.js +99 -0
- package/cli/build/lib/jsonl-events.js +117 -43
- package/cli/package.json +1 -1
- package/client/dist/assets/{OAuthCallback-RXmtS9Xr.js → OAuthCallback-pydLxj3d.js} +1 -1
- package/client/dist/assets/{OAuthDebugCallback-BRtDZYF8.js → OAuthDebugCallback-BLEebYQf.js} +1 -1
- package/client/dist/assets/{index-0DAqp50J.js → index-CVyqQ7s8.js} +4 -4
- package/client/dist/index.html +1 -1
- package/client/package.json +1 -1
- package/package.json +1 -1
- package/server/package.json +1 -1
|
@@ -207,6 +207,105 @@ describe("JSONL Event Emission", () => {
|
|
|
207
207
|
expect(annotations).not.toBeNull();
|
|
208
208
|
expect(annotations?.readOnlyHint).toBe(false); // Should use annotations object value
|
|
209
209
|
});
|
|
210
|
+
// Issue #160: Test non-suffixed annotation property detection
|
|
211
|
+
it("should detect non-suffixed readOnly from annotations object (Issue #160)", () => {
|
|
212
|
+
const tool = {
|
|
213
|
+
name: "domain_search",
|
|
214
|
+
description: "Search emails based on domain name",
|
|
215
|
+
inputSchema: { type: "object" },
|
|
216
|
+
annotations: { readOnly: true }, // Non-suffixed version
|
|
217
|
+
};
|
|
218
|
+
emitToolDiscovered(tool);
|
|
219
|
+
const annotations = emittedEvents[0].annotations;
|
|
220
|
+
expect(annotations).not.toBeNull();
|
|
221
|
+
expect(annotations?.readOnlyHint).toBe(true);
|
|
222
|
+
});
|
|
223
|
+
it("should detect all non-suffixed annotations from annotations object (Issue #160)", () => {
|
|
224
|
+
const tool = {
|
|
225
|
+
name: "full_annotations",
|
|
226
|
+
inputSchema: { type: "object" },
|
|
227
|
+
annotations: {
|
|
228
|
+
readOnly: true,
|
|
229
|
+
destructive: false,
|
|
230
|
+
idempotent: true,
|
|
231
|
+
openWorld: false,
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
emitToolDiscovered(tool);
|
|
235
|
+
const annotations = emittedEvents[0].annotations;
|
|
236
|
+
expect(annotations).not.toBeNull();
|
|
237
|
+
expect(annotations?.readOnlyHint).toBe(true);
|
|
238
|
+
expect(annotations?.destructiveHint).toBe(false);
|
|
239
|
+
expect(annotations?.idempotentHint).toBe(true);
|
|
240
|
+
expect(annotations?.openWorldHint).toBe(false);
|
|
241
|
+
});
|
|
242
|
+
it("should detect non-suffixed readOnly from direct properties (Issue #160)", () => {
|
|
243
|
+
const tool = {
|
|
244
|
+
name: "email_finder",
|
|
245
|
+
inputSchema: { type: "object" },
|
|
246
|
+
readOnly: true, // Direct non-suffixed property
|
|
247
|
+
};
|
|
248
|
+
emitToolDiscovered(tool);
|
|
249
|
+
const annotations = emittedEvents[0].annotations;
|
|
250
|
+
expect(annotations).not.toBeNull();
|
|
251
|
+
expect(annotations?.readOnlyHint).toBe(true);
|
|
252
|
+
});
|
|
253
|
+
it("should detect non-suffixed annotations from metadata object (Issue #160)", () => {
|
|
254
|
+
const tool = {
|
|
255
|
+
name: "metadata_tool",
|
|
256
|
+
inputSchema: { type: "object" },
|
|
257
|
+
metadata: {
|
|
258
|
+
readOnly: true,
|
|
259
|
+
destructive: false,
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
emitToolDiscovered(tool);
|
|
263
|
+
const annotations = emittedEvents[0].annotations;
|
|
264
|
+
expect(annotations).not.toBeNull();
|
|
265
|
+
expect(annotations?.readOnlyHint).toBe(true);
|
|
266
|
+
expect(annotations?.destructiveHint).toBe(false);
|
|
267
|
+
});
|
|
268
|
+
it("should detect non-suffixed annotations from _meta object (Issue #160)", () => {
|
|
269
|
+
const tool = {
|
|
270
|
+
name: "meta_tool",
|
|
271
|
+
inputSchema: { type: "object" },
|
|
272
|
+
_meta: {
|
|
273
|
+
idempotent: true,
|
|
274
|
+
openWorld: false,
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
emitToolDiscovered(tool);
|
|
278
|
+
const annotations = emittedEvents[0].annotations;
|
|
279
|
+
expect(annotations).not.toBeNull();
|
|
280
|
+
expect(annotations?.idempotentHint).toBe(true);
|
|
281
|
+
expect(annotations?.openWorldHint).toBe(false);
|
|
282
|
+
});
|
|
283
|
+
it("should prioritize *Hint over non-suffixed in annotations object (Issue #160)", () => {
|
|
284
|
+
const tool = {
|
|
285
|
+
name: "priority_tool",
|
|
286
|
+
inputSchema: { type: "object" },
|
|
287
|
+
annotations: {
|
|
288
|
+
readOnlyHint: false, // *Hint version should win
|
|
289
|
+
readOnly: true, // Should be ignored
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
emitToolDiscovered(tool);
|
|
293
|
+
const annotations = emittedEvents[0].annotations;
|
|
294
|
+
expect(annotations).not.toBeNull();
|
|
295
|
+
expect(annotations?.readOnlyHint).toBe(false); // *Hint takes priority
|
|
296
|
+
});
|
|
297
|
+
it("should prioritize *Hint over non-suffixed in direct properties (Issue #160)", () => {
|
|
298
|
+
const tool = {
|
|
299
|
+
name: "direct_priority_tool",
|
|
300
|
+
inputSchema: { type: "object" },
|
|
301
|
+
destructiveHint: true, // *Hint version should win
|
|
302
|
+
destructive: false, // Should be ignored
|
|
303
|
+
};
|
|
304
|
+
emitToolDiscovered(tool);
|
|
305
|
+
const annotations = emittedEvents[0].annotations;
|
|
306
|
+
expect(annotations).not.toBeNull();
|
|
307
|
+
expect(annotations?.destructiveHint).toBe(true);
|
|
308
|
+
});
|
|
210
309
|
});
|
|
211
310
|
describe("emitToolsDiscoveryComplete", () => {
|
|
212
311
|
it("should emit tools_discovery_complete with count", () => {
|
|
@@ -70,76 +70,150 @@ export function extractToolParams(schema) {
|
|
|
70
70
|
export function emitToolDiscovered(tool) {
|
|
71
71
|
const params = extractToolParams(tool.inputSchema);
|
|
72
72
|
// Issue #155: Extract annotations from multiple sources (priority order)
|
|
73
|
-
//
|
|
74
|
-
// that
|
|
75
|
-
// not non-suffixed variants like readOnly, destructive, idempotent, openWorld.
|
|
76
|
-
// See AlignmentChecker.resolveAnnotationValue() for full implementation with fallbacks.
|
|
73
|
+
// Issue #160: Also check non-suffixed variants (readOnly, destructive, etc.)
|
|
74
|
+
// for servers that use the shorter property names instead of *Hint versions.
|
|
77
75
|
const toolAny = tool;
|
|
76
|
+
const annotationsAny = tool.annotations;
|
|
78
77
|
// Priority 1: Check tool.annotations object (MCP spec)
|
|
78
|
+
// Issue #160: Use nullish coalescing to fall back to non-suffixed versions
|
|
79
79
|
let readOnlyHint;
|
|
80
80
|
let destructiveHint;
|
|
81
81
|
let idempotentHint;
|
|
82
82
|
let openWorldHint;
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
if (annotationsAny) {
|
|
84
|
+
// Check *Hint version first, fall back to non-suffixed (Issue #160)
|
|
85
|
+
if (typeof annotationsAny.readOnlyHint === "boolean") {
|
|
86
|
+
readOnlyHint = annotationsAny.readOnlyHint;
|
|
87
|
+
}
|
|
88
|
+
else if (typeof annotationsAny.readOnly === "boolean") {
|
|
89
|
+
readOnlyHint = annotationsAny.readOnly;
|
|
90
|
+
}
|
|
91
|
+
if (typeof annotationsAny.destructiveHint === "boolean") {
|
|
92
|
+
destructiveHint = annotationsAny.destructiveHint;
|
|
93
|
+
}
|
|
94
|
+
else if (typeof annotationsAny.destructive === "boolean") {
|
|
95
|
+
destructiveHint = annotationsAny.destructive;
|
|
96
|
+
}
|
|
97
|
+
if (typeof annotationsAny.idempotentHint === "boolean") {
|
|
98
|
+
idempotentHint = annotationsAny.idempotentHint;
|
|
99
|
+
}
|
|
100
|
+
else if (typeof annotationsAny.idempotent === "boolean") {
|
|
101
|
+
idempotentHint = annotationsAny.idempotent;
|
|
102
|
+
}
|
|
103
|
+
if (typeof annotationsAny.openWorldHint === "boolean") {
|
|
104
|
+
openWorldHint = annotationsAny.openWorldHint;
|
|
105
|
+
}
|
|
106
|
+
else if (typeof annotationsAny.openWorld === "boolean") {
|
|
107
|
+
openWorldHint = annotationsAny.openWorld;
|
|
108
|
+
}
|
|
88
109
|
}
|
|
89
110
|
// Priority 2: Check direct properties on tool object
|
|
90
111
|
// Only use if not already found in annotations
|
|
91
|
-
|
|
92
|
-
|
|
112
|
+
// Issue #160: Check both *Hint and non-suffixed versions
|
|
113
|
+
if (readOnlyHint === undefined) {
|
|
114
|
+
if (typeof toolAny.readOnlyHint === "boolean") {
|
|
115
|
+
readOnlyHint = toolAny.readOnlyHint;
|
|
116
|
+
}
|
|
117
|
+
else if (typeof toolAny.readOnly === "boolean") {
|
|
118
|
+
readOnlyHint = toolAny.readOnly;
|
|
119
|
+
}
|
|
93
120
|
}
|
|
94
|
-
if (destructiveHint === undefined
|
|
95
|
-
typeof toolAny.destructiveHint === "boolean") {
|
|
96
|
-
|
|
121
|
+
if (destructiveHint === undefined) {
|
|
122
|
+
if (typeof toolAny.destructiveHint === "boolean") {
|
|
123
|
+
destructiveHint = toolAny.destructiveHint;
|
|
124
|
+
}
|
|
125
|
+
else if (typeof toolAny.destructive === "boolean") {
|
|
126
|
+
destructiveHint = toolAny.destructive;
|
|
127
|
+
}
|
|
97
128
|
}
|
|
98
|
-
if (idempotentHint === undefined
|
|
99
|
-
typeof toolAny.idempotentHint === "boolean") {
|
|
100
|
-
|
|
129
|
+
if (idempotentHint === undefined) {
|
|
130
|
+
if (typeof toolAny.idempotentHint === "boolean") {
|
|
131
|
+
idempotentHint = toolAny.idempotentHint;
|
|
132
|
+
}
|
|
133
|
+
else if (typeof toolAny.idempotent === "boolean") {
|
|
134
|
+
idempotentHint = toolAny.idempotent;
|
|
135
|
+
}
|
|
101
136
|
}
|
|
102
|
-
if (openWorldHint === undefined
|
|
103
|
-
typeof toolAny.openWorldHint === "boolean") {
|
|
104
|
-
|
|
137
|
+
if (openWorldHint === undefined) {
|
|
138
|
+
if (typeof toolAny.openWorldHint === "boolean") {
|
|
139
|
+
openWorldHint = toolAny.openWorldHint;
|
|
140
|
+
}
|
|
141
|
+
else if (typeof toolAny.openWorld === "boolean") {
|
|
142
|
+
openWorldHint = toolAny.openWorld;
|
|
143
|
+
}
|
|
105
144
|
}
|
|
106
145
|
// Priority 3: Check tool.metadata object
|
|
146
|
+
// Issue #160: Check both *Hint and non-suffixed versions
|
|
107
147
|
const metadata = toolAny.metadata;
|
|
108
148
|
if (metadata) {
|
|
109
|
-
if (readOnlyHint === undefined
|
|
110
|
-
typeof metadata.readOnlyHint === "boolean") {
|
|
111
|
-
|
|
149
|
+
if (readOnlyHint === undefined) {
|
|
150
|
+
if (typeof metadata.readOnlyHint === "boolean") {
|
|
151
|
+
readOnlyHint = metadata.readOnlyHint;
|
|
152
|
+
}
|
|
153
|
+
else if (typeof metadata.readOnly === "boolean") {
|
|
154
|
+
readOnlyHint = metadata.readOnly;
|
|
155
|
+
}
|
|
112
156
|
}
|
|
113
|
-
if (destructiveHint === undefined
|
|
114
|
-
typeof metadata.destructiveHint === "boolean") {
|
|
115
|
-
|
|
157
|
+
if (destructiveHint === undefined) {
|
|
158
|
+
if (typeof metadata.destructiveHint === "boolean") {
|
|
159
|
+
destructiveHint = metadata.destructiveHint;
|
|
160
|
+
}
|
|
161
|
+
else if (typeof metadata.destructive === "boolean") {
|
|
162
|
+
destructiveHint = metadata.destructive;
|
|
163
|
+
}
|
|
116
164
|
}
|
|
117
|
-
if (idempotentHint === undefined
|
|
118
|
-
typeof metadata.idempotentHint === "boolean") {
|
|
119
|
-
|
|
165
|
+
if (idempotentHint === undefined) {
|
|
166
|
+
if (typeof metadata.idempotentHint === "boolean") {
|
|
167
|
+
idempotentHint = metadata.idempotentHint;
|
|
168
|
+
}
|
|
169
|
+
else if (typeof metadata.idempotent === "boolean") {
|
|
170
|
+
idempotentHint = metadata.idempotent;
|
|
171
|
+
}
|
|
120
172
|
}
|
|
121
|
-
if (openWorldHint === undefined
|
|
122
|
-
typeof metadata.openWorldHint === "boolean") {
|
|
123
|
-
|
|
173
|
+
if (openWorldHint === undefined) {
|
|
174
|
+
if (typeof metadata.openWorldHint === "boolean") {
|
|
175
|
+
openWorldHint = metadata.openWorldHint;
|
|
176
|
+
}
|
|
177
|
+
else if (typeof metadata.openWorld === "boolean") {
|
|
178
|
+
openWorldHint = metadata.openWorld;
|
|
179
|
+
}
|
|
124
180
|
}
|
|
125
181
|
}
|
|
126
182
|
// Priority 4: Check tool._meta object
|
|
183
|
+
// Issue #160: Check both *Hint and non-suffixed versions
|
|
127
184
|
const _meta = toolAny._meta;
|
|
128
185
|
if (_meta) {
|
|
129
|
-
if (readOnlyHint === undefined
|
|
130
|
-
|
|
186
|
+
if (readOnlyHint === undefined) {
|
|
187
|
+
if (typeof _meta.readOnlyHint === "boolean") {
|
|
188
|
+
readOnlyHint = _meta.readOnlyHint;
|
|
189
|
+
}
|
|
190
|
+
else if (typeof _meta.readOnly === "boolean") {
|
|
191
|
+
readOnlyHint = _meta.readOnly;
|
|
192
|
+
}
|
|
131
193
|
}
|
|
132
|
-
if (destructiveHint === undefined
|
|
133
|
-
typeof _meta.destructiveHint === "boolean") {
|
|
134
|
-
|
|
194
|
+
if (destructiveHint === undefined) {
|
|
195
|
+
if (typeof _meta.destructiveHint === "boolean") {
|
|
196
|
+
destructiveHint = _meta.destructiveHint;
|
|
197
|
+
}
|
|
198
|
+
else if (typeof _meta.destructive === "boolean") {
|
|
199
|
+
destructiveHint = _meta.destructive;
|
|
200
|
+
}
|
|
135
201
|
}
|
|
136
|
-
if (idempotentHint === undefined
|
|
137
|
-
typeof _meta.idempotentHint === "boolean") {
|
|
138
|
-
|
|
202
|
+
if (idempotentHint === undefined) {
|
|
203
|
+
if (typeof _meta.idempotentHint === "boolean") {
|
|
204
|
+
idempotentHint = _meta.idempotentHint;
|
|
205
|
+
}
|
|
206
|
+
else if (typeof _meta.idempotent === "boolean") {
|
|
207
|
+
idempotentHint = _meta.idempotent;
|
|
208
|
+
}
|
|
139
209
|
}
|
|
140
|
-
if (openWorldHint === undefined
|
|
141
|
-
typeof _meta.openWorldHint === "boolean") {
|
|
142
|
-
|
|
210
|
+
if (openWorldHint === undefined) {
|
|
211
|
+
if (typeof _meta.openWorldHint === "boolean") {
|
|
212
|
+
openWorldHint = _meta.openWorldHint;
|
|
213
|
+
}
|
|
214
|
+
else if (typeof _meta.openWorld === "boolean") {
|
|
215
|
+
openWorldHint = _meta.openWorld;
|
|
216
|
+
}
|
|
143
217
|
}
|
|
144
218
|
}
|
|
145
219
|
// Build annotations object if any hints were found
|
package/cli/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-
|
|
1
|
+
import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-CVyqQ7s8.js";
|
|
2
2
|
const OAuthCallback = ({ onConnect }) => {
|
|
3
3
|
const { toast } = useToast();
|
|
4
4
|
const hasProcessedRef = reactExports.useRef(false);
|
package/client/dist/assets/{OAuthDebugCallback-BRtDZYF8.js → OAuthDebugCallback-BLEebYQf.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-
|
|
1
|
+
import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-CVyqQ7s8.js";
|
|
2
2
|
const OAuthDebugCallback = ({ onConnect }) => {
|
|
3
3
|
reactExports.useEffect(() => {
|
|
4
4
|
let isProcessed = false;
|
|
@@ -16373,7 +16373,7 @@ object({
|
|
|
16373
16373
|
token_type_hint: string().optional()
|
|
16374
16374
|
}).strip();
|
|
16375
16375
|
const name = "@bryan-thompson/inspector-assessment-client";
|
|
16376
|
-
const version$1 = "1.36.
|
|
16376
|
+
const version$1 = "1.36.4";
|
|
16377
16377
|
const packageJson = {
|
|
16378
16378
|
name,
|
|
16379
16379
|
version: version$1
|
|
@@ -48920,7 +48920,7 @@ const useTheme = () => {
|
|
|
48920
48920
|
[theme, setThemeWithSideEffect]
|
|
48921
48921
|
);
|
|
48922
48922
|
};
|
|
48923
|
-
const version = "1.36.
|
|
48923
|
+
const version = "1.36.4";
|
|
48924
48924
|
var [createTooltipContext] = createContextScope("Tooltip", [
|
|
48925
48925
|
createPopperScope
|
|
48926
48926
|
]);
|
|
@@ -52515,13 +52515,13 @@ const App = () => {
|
|
|
52515
52515
|
) });
|
|
52516
52516
|
if (window.location.pathname === "/oauth/callback") {
|
|
52517
52517
|
const OAuthCallback = React.lazy(
|
|
52518
|
-
() => __vitePreload(() => import("./OAuthCallback-
|
|
52518
|
+
() => __vitePreload(() => import("./OAuthCallback-pydLxj3d.js"), true ? [] : void 0)
|
|
52519
52519
|
);
|
|
52520
52520
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthCallback, { onConnect: onOAuthConnect }) });
|
|
52521
52521
|
}
|
|
52522
52522
|
if (window.location.pathname === "/oauth/callback/debug") {
|
|
52523
52523
|
const OAuthDebugCallback = React.lazy(
|
|
52524
|
-
() => __vitePreload(() => import("./OAuthDebugCallback-
|
|
52524
|
+
() => __vitePreload(() => import("./OAuthDebugCallback-BLEebYQf.js"), true ? [] : void 0)
|
|
52525
52525
|
);
|
|
52526
52526
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthDebugCallback, { onConnect: onOAuthDebugConnect }) });
|
|
52527
52527
|
}
|
package/client/dist/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/mcp.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>MCP Inspector</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-CVyqQ7s8.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-BoUA5OL1.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/client/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bryan-thompson/inspector-assessment-client",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.4",
|
|
4
4
|
"description": "Client-side application for the Enhanced MCP Inspector with assessment capabilities",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bryan Thompson <bryan@triepod.ai>",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bryan-thompson/inspector-assessment",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.4",
|
|
4
4
|
"description": "Enhanced MCP Inspector with comprehensive assessment capabilities for server validation",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bryan Thompson <bryan@triepod.ai>",
|
package/server/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bryan-thompson/inspector-assessment-server",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.4",
|
|
4
4
|
"description": "Server-side application for the Enhanced MCP Inspector with assessment capabilities",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bryan Thompson <bryan@triepod.ai>",
|