@bryan-thompson/inspector-assessment-client 1.19.3 → 1.19.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/dist/assets/{OAuthCallback-B2AjbBqS.js → OAuthCallback-ByUGVYdZ.js} +1 -1
- package/dist/assets/{OAuthDebugCallback-B3UFm4SC.js → OAuthDebugCallback-D1soBtsd.js} +1 -1
- package/dist/assets/{index-i29GUqYn.js → index-CY09KxrR.js} +80 -25
- package/dist/assets/{index-32-uLPhe.css → index-DiyPO_Zj.css} +3 -0
- package/dist/index.html +2 -2
- package/lib/services/assessment/ResponseValidator.d.ts.map +1 -1
- package/lib/services/assessment/ResponseValidator.js +37 -10
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts +2 -0
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.js +31 -7
- package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/ToolAnnotationAssessor.js +14 -2
- package/lib/utils/schemaUtils.d.ts +13 -0
- package/lib/utils/schemaUtils.d.ts.map +1 -1
- package/lib/utils/schemaUtils.js +25 -0
- package/package.json +1 -1
|
@@ -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-CY09KxrR.js";
|
|
2
2
|
const OAuthCallback = ({ onConnect }) => {
|
|
3
3
|
const { toast } = useToast();
|
|
4
4
|
const hasProcessedRef = reactExports.useRef(false);
|
|
@@ -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-CY09KxrR.js";
|
|
2
2
|
const OAuthDebugCallback = ({ onConnect }) => {
|
|
3
3
|
reactExports.useEffect(() => {
|
|
4
4
|
let isProcessed = false;
|
|
@@ -16320,7 +16320,7 @@ object({
|
|
|
16320
16320
|
token_type_hint: string().optional()
|
|
16321
16321
|
}).strip();
|
|
16322
16322
|
const name = "@bryan-thompson/inspector-assessment-client";
|
|
16323
|
-
const version$1 = "1.19.
|
|
16323
|
+
const version$1 = "1.19.3";
|
|
16324
16324
|
const packageJson = {
|
|
16325
16325
|
name,
|
|
16326
16326
|
version: version$1
|
|
@@ -23649,6 +23649,21 @@ function validateToolOutput(toolName, structuredContent) {
|
|
|
23649
23649
|
function hasOutputSchema(toolName) {
|
|
23650
23650
|
return toolOutputValidators.has(toolName);
|
|
23651
23651
|
}
|
|
23652
|
+
function tryExtractJsonFromContent(content) {
|
|
23653
|
+
if (!content || !Array.isArray(content)) {
|
|
23654
|
+
return null;
|
|
23655
|
+
}
|
|
23656
|
+
const textBlocks = content.filter((block) => block.type === "text");
|
|
23657
|
+
for (const block of textBlocks) {
|
|
23658
|
+
if (!block.text) continue;
|
|
23659
|
+
try {
|
|
23660
|
+
return JSON.parse(block.text);
|
|
23661
|
+
} catch {
|
|
23662
|
+
continue;
|
|
23663
|
+
}
|
|
23664
|
+
}
|
|
23665
|
+
return null;
|
|
23666
|
+
}
|
|
23652
23667
|
function generateDefaultValue(schema, propertyName, parentSchema) {
|
|
23653
23668
|
if ("default" in schema && schema.default !== void 0) {
|
|
23654
23669
|
return schema.default;
|
|
@@ -45337,7 +45352,7 @@ const useTheme = () => {
|
|
|
45337
45352
|
[theme, setThemeWithSideEffect]
|
|
45338
45353
|
);
|
|
45339
45354
|
};
|
|
45340
|
-
const version = "1.19.
|
|
45355
|
+
const version = "1.19.3";
|
|
45341
45356
|
var [createTooltipContext] = createContextScope("Tooltip", [
|
|
45342
45357
|
createPopperScope
|
|
45343
45358
|
]);
|
|
@@ -47362,16 +47377,26 @@ const ToolResults = ({
|
|
|
47362
47377
|
let validationResult = null;
|
|
47363
47378
|
const toolHasOutputSchema = selectedTool && hasOutputSchema(selectedTool.name);
|
|
47364
47379
|
if (toolHasOutputSchema) {
|
|
47365
|
-
if (
|
|
47366
|
-
validationResult = {
|
|
47367
|
-
isValid: false,
|
|
47368
|
-
error: "Tool has an output schema but did not return structured content"
|
|
47369
|
-
};
|
|
47370
|
-
} else if (structuredResult.structuredContent) {
|
|
47380
|
+
if (structuredResult.structuredContent) {
|
|
47371
47381
|
validationResult = validateToolOutput(
|
|
47372
47382
|
selectedTool.name,
|
|
47373
47383
|
structuredResult.structuredContent
|
|
47374
47384
|
);
|
|
47385
|
+
} else if (!isError) {
|
|
47386
|
+
const extractedJson = tryExtractJsonFromContent(
|
|
47387
|
+
structuredResult.content
|
|
47388
|
+
);
|
|
47389
|
+
if (extractedJson !== null) {
|
|
47390
|
+
validationResult = validateToolOutput(
|
|
47391
|
+
selectedTool.name,
|
|
47392
|
+
extractedJson
|
|
47393
|
+
);
|
|
47394
|
+
} else {
|
|
47395
|
+
validationResult = {
|
|
47396
|
+
isValid: false,
|
|
47397
|
+
error: "Tool has output schema but response contains no valid JSON"
|
|
47398
|
+
};
|
|
47399
|
+
}
|
|
47375
47400
|
}
|
|
47376
47401
|
}
|
|
47377
47402
|
let compatibilityResult = null;
|
|
@@ -48329,7 +48354,11 @@ class MCPSpecComplianceAssessor extends BaseAssessor {
|
|
|
48329
48354
|
const metadataHints = this.extractMetadataHints(context);
|
|
48330
48355
|
const checksArray = Object.values(protocolChecks);
|
|
48331
48356
|
const passedCount = checksArray.filter((c) => c.passed).length;
|
|
48332
|
-
const
|
|
48357
|
+
const totalChecks = checksArray.length;
|
|
48358
|
+
const complianceScore = passedCount / totalChecks * 100;
|
|
48359
|
+
this.log(
|
|
48360
|
+
`MCP Compliance: ${passedCount}/${totalChecks} checks passed (${complianceScore.toFixed(1)}%)`
|
|
48361
|
+
);
|
|
48333
48362
|
let status;
|
|
48334
48363
|
if (!protocolChecks.serverInfoValidity.passed) {
|
|
48335
48364
|
status = "FAIL";
|
|
@@ -48388,13 +48417,17 @@ class MCPSpecComplianceAssessor extends BaseAssessor {
|
|
|
48388
48417
|
}
|
|
48389
48418
|
/**
|
|
48390
48419
|
* Check JSON-RPC 2.0 compliance
|
|
48420
|
+
* A proper JSON-RPC response should have the correct structure even for errors.
|
|
48391
48421
|
*/
|
|
48392
48422
|
async checkJsonRpcCompliance(callTool) {
|
|
48393
48423
|
try {
|
|
48394
48424
|
const result = await callTool("list", {});
|
|
48395
|
-
|
|
48425
|
+
const hasValidStructure = result !== null && (Array.isArray(result.content) || result.isError !== void 0);
|
|
48426
|
+
return { passed: hasValidStructure, rawResponse: result };
|
|
48396
48427
|
} catch (error) {
|
|
48397
|
-
|
|
48428
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
48429
|
+
const isStructuredError = errorMessage.includes("MCP error") || errorMessage.includes("jsonrpc") || errorMessage.includes("-32");
|
|
48430
|
+
return { passed: isStructuredError, rawResponse: error };
|
|
48398
48431
|
}
|
|
48399
48432
|
}
|
|
48400
48433
|
/**
|
|
@@ -48455,6 +48488,7 @@ class MCPSpecComplianceAssessor extends BaseAssessor {
|
|
|
48455
48488
|
}
|
|
48456
48489
|
/**
|
|
48457
48490
|
* Check error response compliance
|
|
48491
|
+
* Validates that the server returns proper error responses for invalid inputs.
|
|
48458
48492
|
*/
|
|
48459
48493
|
async checkErrorResponses(tools, callTool) {
|
|
48460
48494
|
try {
|
|
@@ -48463,9 +48497,14 @@ class MCPSpecComplianceAssessor extends BaseAssessor {
|
|
|
48463
48497
|
const testTool = tools[0];
|
|
48464
48498
|
try {
|
|
48465
48499
|
const result = await callTool(testTool.name, { invalid_param: "test" });
|
|
48466
|
-
|
|
48500
|
+
const isErrorResponse = result.isError === true;
|
|
48501
|
+
const hasContent = Array.isArray(result.content);
|
|
48502
|
+
const passed = isErrorResponse && hasContent || !isErrorResponse && hasContent;
|
|
48503
|
+
return { passed, rawResponse: result };
|
|
48467
48504
|
} catch (error) {
|
|
48468
|
-
|
|
48505
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
48506
|
+
const isStructuredError = errorMessage.includes("MCP error") || errorMessage.includes("-32") || errorMessage.includes("jsonrpc");
|
|
48507
|
+
return { passed: isStructuredError, rawResponse: error };
|
|
48469
48508
|
}
|
|
48470
48509
|
} catch (error) {
|
|
48471
48510
|
return { passed: false, rawResponse: error };
|
|
@@ -49373,13 +49412,7 @@ class ResponseValidator {
|
|
|
49373
49412
|
let outputSchemaValidation;
|
|
49374
49413
|
const toolHasOutputSchema = hasOutputSchema(context.tool.name);
|
|
49375
49414
|
if (toolHasOutputSchema) {
|
|
49376
|
-
if (
|
|
49377
|
-
outputSchemaValidation = {
|
|
49378
|
-
hasOutputSchema: true,
|
|
49379
|
-
isValid: false,
|
|
49380
|
-
error: "Tool has output schema but did not return structuredContent"
|
|
49381
|
-
};
|
|
49382
|
-
} else {
|
|
49415
|
+
if (hasStructuredContent) {
|
|
49383
49416
|
const validation2 = validateToolOutput(
|
|
49384
49417
|
context.tool.name,
|
|
49385
49418
|
response.structuredContent
|
|
@@ -49389,6 +49422,27 @@ class ResponseValidator {
|
|
|
49389
49422
|
isValid: validation2.isValid,
|
|
49390
49423
|
error: validation2.error
|
|
49391
49424
|
};
|
|
49425
|
+
} else {
|
|
49426
|
+
const extractedJson = tryExtractJsonFromContent(
|
|
49427
|
+
content || []
|
|
49428
|
+
);
|
|
49429
|
+
if (extractedJson !== null) {
|
|
49430
|
+
const validation2 = validateToolOutput(
|
|
49431
|
+
context.tool.name,
|
|
49432
|
+
extractedJson
|
|
49433
|
+
);
|
|
49434
|
+
outputSchemaValidation = {
|
|
49435
|
+
hasOutputSchema: true,
|
|
49436
|
+
isValid: validation2.isValid,
|
|
49437
|
+
error: validation2.error
|
|
49438
|
+
};
|
|
49439
|
+
} else {
|
|
49440
|
+
outputSchemaValidation = {
|
|
49441
|
+
hasOutputSchema: true,
|
|
49442
|
+
isValid: false,
|
|
49443
|
+
error: "Tool has output schema but response contains no valid JSON"
|
|
49444
|
+
};
|
|
49445
|
+
}
|
|
49392
49446
|
}
|
|
49393
49447
|
}
|
|
49394
49448
|
return {
|
|
@@ -49647,9 +49701,10 @@ class ResponseValidator {
|
|
|
49647
49701
|
);
|
|
49648
49702
|
const toolName = context.tool.name.toLowerCase();
|
|
49649
49703
|
const isValidationExpected = (
|
|
49650
|
-
// CRUD operations
|
|
49651
|
-
toolName.includes("create") || toolName.includes("update") || toolName.includes("delete") || toolName.includes("get") || toolName.includes("fetch") || toolName.includes("read") || toolName.includes("write") || // Data operations
|
|
49652
|
-
toolName.includes("query") || toolName.includes("search") || toolName.includes("find") || toolName.includes("list") || //
|
|
49704
|
+
// CRUD operations (including add/remove variants)
|
|
49705
|
+
toolName.includes("create") || toolName.includes("add") || toolName.includes("insert") || toolName.includes("update") || toolName.includes("modify") || toolName.includes("set") || toolName.includes("delete") || toolName.includes("remove") || toolName.includes("get") || toolName.includes("fetch") || toolName.includes("read") || toolName.includes("write") || // Data operations
|
|
49706
|
+
toolName.includes("query") || toolName.includes("search") || toolName.includes("find") || toolName.includes("list") || // Entity/resource operations (knowledge graphs, databases)
|
|
49707
|
+
toolName.includes("entity") || toolName.includes("entities") || toolName.includes("relation") || toolName.includes("observation") || toolName.includes("node") || toolName.includes("edge") || toolName.includes("record") || // State operations
|
|
49653
49708
|
toolName.includes("move") || toolName.includes("copy") || toolName.includes("duplicate") || toolName.includes("archive") || // Relationship operations
|
|
49654
49709
|
toolName.includes("link") || toolName.includes("associate") || toolName.includes("connect") || toolName.includes("attach") || // API/scraping operations
|
|
49655
49710
|
toolName.includes("scrape") || toolName.includes("crawl") || toolName.includes("map") || toolName.includes("extract") || toolName.includes("parse") || toolName.includes("analyze") || toolName.includes("process")
|
|
@@ -59102,13 +59157,13 @@ const App = () => {
|
|
|
59102
59157
|
) });
|
|
59103
59158
|
if (window.location.pathname === "/oauth/callback") {
|
|
59104
59159
|
const OAuthCallback = React.lazy(
|
|
59105
|
-
() => __vitePreload(() => import("./OAuthCallback-
|
|
59160
|
+
() => __vitePreload(() => import("./OAuthCallback-ByUGVYdZ.js"), true ? [] : void 0)
|
|
59106
59161
|
);
|
|
59107
59162
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthCallback, { onConnect: onOAuthConnect }) });
|
|
59108
59163
|
}
|
|
59109
59164
|
if (window.location.pathname === "/oauth/callback/debug") {
|
|
59110
59165
|
const OAuthDebugCallback = React.lazy(
|
|
59111
|
-
() => __vitePreload(() => import("./OAuthDebugCallback-
|
|
59166
|
+
() => __vitePreload(() => import("./OAuthDebugCallback-D1soBtsd.js"), true ? [] : void 0)
|
|
59112
59167
|
);
|
|
59113
59168
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthDebugCallback, { onConnect: onOAuthDebugConnect }) });
|
|
59114
59169
|
}
|
package/dist/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
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-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-CY09KxrR.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DiyPO_Zj.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root" class="w-full"></div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResponseValidator.d.ts","sourceRoot":"","sources":["../../../src/services/assessment/ResponseValidator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,2BAA2B,EAC3B,IAAI,EACL,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"ResponseValidator.d.ts","sourceRoot":"","sources":["../../../src/services/assessment/ResponseValidator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,2BAA2B,EAC3B,IAAI,EACL,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAOzD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,cAAc,EACV,eAAe,GACf,mBAAmB,GACnB,mBAAmB,GACnB,QAAQ,GACR,OAAO,CAAC;IACZ,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,QAAQ,EAAE,2BAA2B,CAAC;IACtC,gBAAgB,CAAC,EAAE,YAAY,GAAG,WAAW,GAAG,UAAU,GAAG,YAAY,CAAC;CAC3E;AAED,qBAAa,iBAAiB;IAC5B;;OAEG;IACH,MAAM,CAAC,uBAAuB,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB;IAoG5E;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB;IAgHrE;;;OAGG;IACH,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO;IAgThE;;OAEG;IACH,MAAM,CAAC,0BAA0B,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM;CAsBvE"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Response Validator for MCP Tool Testing
|
|
3
3
|
* Validates that tool responses are actually functional, not just present
|
|
4
4
|
*/
|
|
5
|
-
import { validateToolOutput, hasOutputSchema } from "../../utils/schemaUtils.js";
|
|
5
|
+
import { validateToolOutput, hasOutputSchema, tryExtractJsonFromContent, } from "../../utils/schemaUtils.js";
|
|
6
6
|
export class ResponseValidator {
|
|
7
7
|
/**
|
|
8
8
|
* Extract response metadata including content types, structuredContent, and _meta
|
|
@@ -45,14 +45,8 @@ export class ResponseValidator {
|
|
|
45
45
|
let outputSchemaValidation;
|
|
46
46
|
const toolHasOutputSchema = hasOutputSchema(context.tool.name);
|
|
47
47
|
if (toolHasOutputSchema) {
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
hasOutputSchema: true,
|
|
51
|
-
isValid: false,
|
|
52
|
-
error: "Tool has output schema but did not return structuredContent",
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
48
|
+
if (hasStructuredContent) {
|
|
49
|
+
// Primary path: validate structuredContent
|
|
56
50
|
const validation = validateToolOutput(context.tool.name, response.structuredContent);
|
|
57
51
|
outputSchemaValidation = {
|
|
58
52
|
hasOutputSchema: true,
|
|
@@ -60,6 +54,26 @@ export class ResponseValidator {
|
|
|
60
54
|
error: validation.error,
|
|
61
55
|
};
|
|
62
56
|
}
|
|
57
|
+
else {
|
|
58
|
+
// Fallback: try to extract JSON from content[] text blocks
|
|
59
|
+
// MCP allows tools to return valid JSON in standard content blocks
|
|
60
|
+
const extractedJson = tryExtractJsonFromContent(content || []);
|
|
61
|
+
if (extractedJson !== null) {
|
|
62
|
+
const validation = validateToolOutput(context.tool.name, extractedJson);
|
|
63
|
+
outputSchemaValidation = {
|
|
64
|
+
hasOutputSchema: true,
|
|
65
|
+
isValid: validation.isValid,
|
|
66
|
+
error: validation.error,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
outputSchemaValidation = {
|
|
71
|
+
hasOutputSchema: true,
|
|
72
|
+
isValid: false,
|
|
73
|
+
error: "Tool has output schema but response contains no valid JSON",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
63
77
|
}
|
|
64
78
|
return {
|
|
65
79
|
contentTypes,
|
|
@@ -330,10 +344,15 @@ export class ResponseValidator {
|
|
|
330
344
|
// Check tool operation type - resource operations are expected to validate
|
|
331
345
|
const toolName = context.tool.name.toLowerCase();
|
|
332
346
|
const isValidationExpected =
|
|
333
|
-
// CRUD operations
|
|
347
|
+
// CRUD operations (including add/remove variants)
|
|
334
348
|
toolName.includes("create") ||
|
|
349
|
+
toolName.includes("add") ||
|
|
350
|
+
toolName.includes("insert") ||
|
|
335
351
|
toolName.includes("update") ||
|
|
352
|
+
toolName.includes("modify") ||
|
|
353
|
+
toolName.includes("set") ||
|
|
336
354
|
toolName.includes("delete") ||
|
|
355
|
+
toolName.includes("remove") ||
|
|
337
356
|
toolName.includes("get") ||
|
|
338
357
|
toolName.includes("fetch") ||
|
|
339
358
|
toolName.includes("read") ||
|
|
@@ -343,6 +362,14 @@ export class ResponseValidator {
|
|
|
343
362
|
toolName.includes("search") ||
|
|
344
363
|
toolName.includes("find") ||
|
|
345
364
|
toolName.includes("list") ||
|
|
365
|
+
// Entity/resource operations (knowledge graphs, databases)
|
|
366
|
+
toolName.includes("entity") ||
|
|
367
|
+
toolName.includes("entities") ||
|
|
368
|
+
toolName.includes("relation") ||
|
|
369
|
+
toolName.includes("observation") ||
|
|
370
|
+
toolName.includes("node") ||
|
|
371
|
+
toolName.includes("edge") ||
|
|
372
|
+
toolName.includes("record") ||
|
|
346
373
|
// State operations
|
|
347
374
|
toolName.includes("move") ||
|
|
348
375
|
toolName.includes("copy") ||
|
|
@@ -19,6 +19,7 @@ export declare class MCPSpecComplianceAssessor extends BaseAssessor {
|
|
|
19
19
|
private extractProtocolVersion;
|
|
20
20
|
/**
|
|
21
21
|
* Check JSON-RPC 2.0 compliance
|
|
22
|
+
* A proper JSON-RPC response should have the correct structure even for errors.
|
|
22
23
|
*/
|
|
23
24
|
private checkJsonRpcCompliance;
|
|
24
25
|
/**
|
|
@@ -31,6 +32,7 @@ export declare class MCPSpecComplianceAssessor extends BaseAssessor {
|
|
|
31
32
|
private checkSchemaCompliance;
|
|
32
33
|
/**
|
|
33
34
|
* Check error response compliance
|
|
35
|
+
* Validates that the server returns proper error responses for invalid inputs.
|
|
34
36
|
*/
|
|
35
37
|
private checkErrorResponses;
|
|
36
38
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MCPSpecComplianceAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/MCPSpecComplianceAssessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,2BAA2B,EAM3B,uBAAuB,EAGxB,MAAM,uBAAuB,CAAC;AAO/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,qBAAa,yBAA0B,SAAQ,YAAY;IACzD,OAAO,CAAC,GAAG,CAAc;gBAEb,MAAM,EAAE,uBAAuB;IAK3C;;;OAGG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"MCPSpecComplianceAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/MCPSpecComplianceAssessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,2BAA2B,EAM3B,uBAAuB,EAGxB,MAAM,uBAAuB,CAAC;AAO/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,qBAAa,yBAA0B,SAAQ,YAAY;IACzD,OAAO,CAAC,GAAG,CAAc;gBAEb,MAAM,EAAE,uBAAuB;IAK3C;;;OAGG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,2BAA2B,CAAC;IAmHvC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAwB9B;;;OAGG;YACW,sBAAsB;IA6BpC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAyB/B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAyC7B;;;OAGG;YACW,mBAAmB;IAsCjC;;OAEG;IACH,OAAO,CAAC,4BAA4B;IAiBpC;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IA0FnC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAyFjC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA4B9B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA2C7B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAoF5B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAyBjC;;OAEG;IACH,OAAO,CAAC,6BAA6B;CA0DtC"}
|
|
@@ -74,7 +74,10 @@ export class MCPSpecComplianceAssessor extends BaseAssessor {
|
|
|
74
74
|
// Calculate score based ONLY on protocol checks (reliable)
|
|
75
75
|
const checksArray = Object.values(protocolChecks);
|
|
76
76
|
const passedCount = checksArray.filter((c) => c.passed).length;
|
|
77
|
-
const
|
|
77
|
+
const totalChecks = checksArray.length;
|
|
78
|
+
const complianceScore = (passedCount / totalChecks) * 100;
|
|
79
|
+
// Log score/check consistency for debugging
|
|
80
|
+
this.log(`MCP Compliance: ${passedCount}/${totalChecks} checks passed (${complianceScore.toFixed(1)}%)`);
|
|
78
81
|
// Determine status based on protocol checks only
|
|
79
82
|
let status;
|
|
80
83
|
if (!protocolChecks.serverInfoValidity.passed) {
|
|
@@ -133,18 +136,27 @@ export class MCPSpecComplianceAssessor extends BaseAssessor {
|
|
|
133
136
|
}
|
|
134
137
|
/**
|
|
135
138
|
* Check JSON-RPC 2.0 compliance
|
|
139
|
+
* A proper JSON-RPC response should have the correct structure even for errors.
|
|
136
140
|
*/
|
|
137
141
|
async checkJsonRpcCompliance(callTool) {
|
|
138
142
|
try {
|
|
139
143
|
// Test basic JSON-RPC structure by making a simple call
|
|
140
144
|
// If we can call any tool, JSON-RPC is working
|
|
141
145
|
const result = await callTool("list", {});
|
|
142
|
-
|
|
146
|
+
// Check if result has valid structure (content array or isError flag)
|
|
147
|
+
const hasValidStructure = result !== null &&
|
|
148
|
+
(Array.isArray(result.content) || result.isError !== undefined);
|
|
149
|
+
return { passed: hasValidStructure, rawResponse: result };
|
|
143
150
|
}
|
|
144
151
|
catch (error) {
|
|
145
|
-
// If
|
|
146
|
-
//
|
|
147
|
-
|
|
152
|
+
// If we get a structured error with proper JSON-RPC format, that's still valid
|
|
153
|
+
// But if it's a raw exception, JSON-RPC compliance failed
|
|
154
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
155
|
+
// Structured MCP errors indicate JSON-RPC is working
|
|
156
|
+
const isStructuredError = errorMessage.includes("MCP error") ||
|
|
157
|
+
errorMessage.includes("jsonrpc") ||
|
|
158
|
+
errorMessage.includes("-32");
|
|
159
|
+
return { passed: isStructuredError, rawResponse: error };
|
|
148
160
|
}
|
|
149
161
|
}
|
|
150
162
|
/**
|
|
@@ -208,6 +220,7 @@ export class MCPSpecComplianceAssessor extends BaseAssessor {
|
|
|
208
220
|
}
|
|
209
221
|
/**
|
|
210
222
|
* Check error response compliance
|
|
223
|
+
* Validates that the server returns proper error responses for invalid inputs.
|
|
211
224
|
*/
|
|
212
225
|
async checkErrorResponses(tools, callTool) {
|
|
213
226
|
try {
|
|
@@ -217,10 +230,21 @@ export class MCPSpecComplianceAssessor extends BaseAssessor {
|
|
|
217
230
|
const testTool = tools[0];
|
|
218
231
|
try {
|
|
219
232
|
const result = await callTool(testTool.name, { invalid_param: "test" });
|
|
220
|
-
|
|
233
|
+
// Server returned a result - check if it's a proper error response
|
|
234
|
+
// or if it gracefully handled the invalid input
|
|
235
|
+
const isErrorResponse = result.isError === true;
|
|
236
|
+
const hasContent = Array.isArray(result.content);
|
|
237
|
+
// Pass if: it's marked as error with proper structure, OR it handled gracefully with content
|
|
238
|
+
const passed = (isErrorResponse && hasContent) || (!isErrorResponse && hasContent);
|
|
239
|
+
return { passed, rawResponse: result };
|
|
221
240
|
}
|
|
222
241
|
catch (error) {
|
|
223
|
-
|
|
242
|
+
// Check if the error is a structured MCP error (proper error handling)
|
|
243
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
244
|
+
const isStructuredError = errorMessage.includes("MCP error") ||
|
|
245
|
+
errorMessage.includes("-32") ||
|
|
246
|
+
errorMessage.includes("jsonrpc");
|
|
247
|
+
return { passed: isStructuredError, rawResponse: error };
|
|
224
248
|
}
|
|
225
249
|
}
|
|
226
250
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolAnnotationAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ToolAnnotationAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EAKpB,uBAAuB,EAExB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAK9B,MAAM,8BAA8B,CAAC;AAmNtC;;GAEG;AACH,MAAM,WAAW,4BAA6B,SAAQ,oBAAoB;IACxE,eAAe,CAAC,EAAE;QAChB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,mBAAmB,EAAE,OAAO,CAAC;QAC7B,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,oBAAoB,EAAE;YACpB,YAAY,CAAC,EAAE,OAAO,CAAC;YACvB,eAAe,CAAC,EAAE,OAAO,CAAC;YAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;SAC1B,CAAC;QACF,oBAAoB,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAAC;KAC7C,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,gCAAiC,SAAQ,wBAAwB;IAChF,WAAW,EAAE,4BAA4B,EAAE,CAAC;IAC5C,cAAc,EAAE,OAAO,CAAC;IACxB,2BAA2B,EAAE,4BAA4B,EAAE,CAAC;CAC7D;AAKD,qBAAa,sBAAuB,SAAQ,YAAY;IACtD,OAAO,CAAC,YAAY,CAAC,CAAmB;IACxC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,kBAAkB,CAAC,CAA2B;gBAE1C,MAAM,EAAE,uBAAuB;IAM3C;;OAEG;IACH,qBAAqB,IAAI,wBAAwB,GAAG,SAAS;IAI7D;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAK7C;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAK/C;;OAEG;IACH,eAAe,IAAI,OAAO;IAO1B;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,wBAAwB,GAAG,gCAAgC,CAAC;IA4SvE;;OAEG;YACW,0BAA0B;IA+IxC;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAiCnC;;OAEG;IACH,OAAO,CAAC,+BAA+B;IAoFvC;;;OAGG;IACH,OAAO,CAAC,UAAU;IA2HlB;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IA2DnC;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB;IAyE1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuBzB;;;OAGG;IACH,OAAO,CAAC,aAAa;
|
|
1
|
+
{"version":3,"file":"ToolAnnotationAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ToolAnnotationAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EACV,wBAAwB,EACxB,oBAAoB,EAKpB,uBAAuB,EAExB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAK9B,MAAM,8BAA8B,CAAC;AAmNtC;;GAEG;AACH,MAAM,WAAW,4BAA6B,SAAQ,oBAAoB;IACxE,eAAe,CAAC,EAAE;QAChB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,mBAAmB,EAAE,OAAO,CAAC;QAC7B,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,oBAAoB,EAAE;YACpB,YAAY,CAAC,EAAE,OAAO,CAAC;YACvB,eAAe,CAAC,EAAE,OAAO,CAAC;YAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;SAC1B,CAAC;QACF,oBAAoB,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAAC;KAC7C,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,gCAAiC,SAAQ,wBAAwB;IAChF,WAAW,EAAE,4BAA4B,EAAE,CAAC;IAC5C,cAAc,EAAE,OAAO,CAAC;IACxB,2BAA2B,EAAE,4BAA4B,EAAE,CAAC;CAC7D;AAKD,qBAAa,sBAAuB,SAAQ,YAAY;IACtD,OAAO,CAAC,YAAY,CAAC,CAAmB;IACxC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,kBAAkB,CAAC,CAA2B;gBAE1C,MAAM,EAAE,uBAAuB;IAM3C;;OAEG;IACH,qBAAqB,IAAI,wBAAwB,GAAG,SAAS;IAI7D;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAK7C;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAK/C;;OAEG;IACH,eAAe,IAAI,OAAO;IAO1B;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,wBAAwB,GAAG,gCAAgC,CAAC;IA4SvE;;OAEG;YACW,0BAA0B;IA+IxC;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAiCnC;;OAEG;IACH,OAAO,CAAC,+BAA+B;IAoFvC;;;OAGG;IACH,OAAO,CAAC,UAAU;IA2HlB;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IA2DnC;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB;IAyE1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuBzB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAkKrB;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IA0DjC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiDxB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmC3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CA2ChC"}
|
|
@@ -916,8 +916,20 @@ export class ToolAnnotationAssessor extends BaseAssessor {
|
|
|
916
916
|
isAmbiguous: false,
|
|
917
917
|
};
|
|
918
918
|
case "write": {
|
|
919
|
-
//
|
|
920
|
-
//
|
|
919
|
+
// CREATE operations are NEVER destructive - they only ADD new data
|
|
920
|
+
// Only UPDATE/MODIFY operations can be considered destructive when they modify existing data
|
|
921
|
+
const isCreateOperation = /^(create|add|insert|new|generate)[_-]/i.test(toolName);
|
|
922
|
+
if (isCreateOperation) {
|
|
923
|
+
return {
|
|
924
|
+
expectedReadOnly: false,
|
|
925
|
+
expectedDestructive: false,
|
|
926
|
+
reason: `Tool name matches create pattern: ${patternMatch.pattern} - create operations only add data and are not destructive`,
|
|
927
|
+
confidence: "high",
|
|
928
|
+
isAmbiguous: false,
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
// Three-Tier Classification: Check persistence model for UPDATE/MODIFY operations
|
|
932
|
+
// If immediate persistence detected, update operations should be marked destructive
|
|
921
933
|
const descriptionCheck = checkDescriptionForImmediatePersistence(description || "");
|
|
922
934
|
// Priority 1: Description explicitly indicates deferred persistence
|
|
923
935
|
if (descriptionCheck.indicatesDeferred) {
|
|
@@ -31,6 +31,19 @@ export declare function validateToolOutput(toolName: string, structuredContent:
|
|
|
31
31
|
* @returns true if the tool has an output schema
|
|
32
32
|
*/
|
|
33
33
|
export declare function hasOutputSchema(toolName: string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Attempts to extract JSON from content[] text blocks.
|
|
36
|
+
* Used as fallback when structuredContent is not present.
|
|
37
|
+
* MCP allows tools to return valid JSON in standard content blocks
|
|
38
|
+
* even when they define an outputSchema.
|
|
39
|
+
* @param content Array of content blocks from tool response
|
|
40
|
+
* @returns Parsed JSON object or null if no valid JSON found
|
|
41
|
+
*/
|
|
42
|
+
export declare function tryExtractJsonFromContent(content: Array<{
|
|
43
|
+
type: string;
|
|
44
|
+
text?: string;
|
|
45
|
+
[key: string]: unknown;
|
|
46
|
+
}>): unknown | null;
|
|
34
47
|
/**
|
|
35
48
|
* Generates a default value based on a JSON schema type
|
|
36
49
|
* @param schema The JSON schema definition
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemaUtils.d.ts","sourceRoot":"","sources":["../../src/utils/schemaUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAc,MAAM,aAAa,CAAC;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAQ/E;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAe1D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,GACf,gBAAgB,GAAG,SAAS,CAE9B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,OAAO,GACzB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAetC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,cAAc,GAC5B,SAAS,CAkDX;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,GACrB,OAAO,CAET;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,cAAc,GACzB,cAAc,CAiChB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CA4FzE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKpD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CA+B5E"}
|
|
1
|
+
{"version":3,"file":"schemaUtils.d.ts","sourceRoot":"","sources":["../../src/utils/schemaUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAc,MAAM,aAAa,CAAC;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAQ/E;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAe1D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,GACf,gBAAgB,GAAG,SAAS,CAE9B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,OAAO,GACzB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAetC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC,GACtE,OAAO,GAAG,IAAI,CAgBhB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,cAAc,GAC5B,SAAS,CAkDX;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,GACrB,OAAO,CAET;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,cAAc,GACzB,cAAc,CAiChB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CA4FzE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKpD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CA+B5E"}
|
package/lib/utils/schemaUtils.js
CHANGED
|
@@ -60,6 +60,31 @@ export function validateToolOutput(toolName, structuredContent) {
|
|
|
60
60
|
export function hasOutputSchema(toolName) {
|
|
61
61
|
return toolOutputValidators.has(toolName);
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Attempts to extract JSON from content[] text blocks.
|
|
65
|
+
* Used as fallback when structuredContent is not present.
|
|
66
|
+
* MCP allows tools to return valid JSON in standard content blocks
|
|
67
|
+
* even when they define an outputSchema.
|
|
68
|
+
* @param content Array of content blocks from tool response
|
|
69
|
+
* @returns Parsed JSON object or null if no valid JSON found
|
|
70
|
+
*/
|
|
71
|
+
export function tryExtractJsonFromContent(content) {
|
|
72
|
+
if (!content || !Array.isArray(content)) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const textBlocks = content.filter((block) => block.type === "text");
|
|
76
|
+
for (const block of textBlocks) {
|
|
77
|
+
if (!block.text)
|
|
78
|
+
continue;
|
|
79
|
+
try {
|
|
80
|
+
return JSON.parse(block.text);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
63
88
|
/**
|
|
64
89
|
* Generates a default value based on a JSON schema type
|
|
65
90
|
* @param schema The JSON schema definition
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bryan-thompson/inspector-assessment-client",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.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>",
|