@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.
@@ -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-i29GUqYn.js";
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-i29GUqYn.js";
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.2";
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.2";
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 (!structuredResult.structuredContent && !isError) {
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 complianceScore = passedCount / checksArray.length * 100;
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
- return { passed: result !== null, rawResponse: result };
48425
+ const hasValidStructure = result !== null && (Array.isArray(result.content) || result.isError !== void 0);
48426
+ return { passed: hasValidStructure, rawResponse: result };
48396
48427
  } catch (error) {
48397
- return { passed: true, rawResponse: error };
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
- return { passed: true, rawResponse: result };
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
- return { passed: true, rawResponse: error };
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 (!hasStructuredContent) {
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") || // State operations
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-B2AjbBqS.js"), true ? [] : void 0)
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-B3UFm4SC.js"), true ? [] : void 0)
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
  }
@@ -956,6 +956,9 @@ video {
956
956
  -webkit-box-orient: vertical;
957
957
  -webkit-line-clamp: 2;
958
958
  }
959
+ .\!block {
960
+ display: block !important;
961
+ }
959
962
  .block {
960
963
  display: block;
961
964
  }
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-i29GUqYn.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-32-uLPhe.css">
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;AAGzD,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;IA8E5E;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB;IAgHrE;;;OAGG;IACH,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO;IAmShE;;OAEG;IACH,MAAM,CAAC,0BAA0B,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM;CAsBvE"}
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 (!hasStructuredContent) {
49
- outputSchemaValidation = {
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;IA6GvC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAwB9B;;OAEG;YACW,sBAAsB;IAkBpC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAyB/B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAyC7B;;OAEG;YACW,mBAAmB;IAwBjC;;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"}
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 complianceScore = (passedCount / checksArray.length) * 100;
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
- return { passed: result !== null, rawResponse: result };
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 call fails, that's actually expected for many tools
146
- // The fact that we got a structured response means JSON-RPC works
147
- return { passed: true, rawResponse: error };
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
- return { passed: true, rawResponse: result }; // Server handled gracefully
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
- return { passed: true, rawResponse: error }; // Server provided error response
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;IAoJrB;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IA0DjC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiDxB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmC3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CA2ChC"}
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
- // Three-Tier Classification: Check persistence model for write operations
920
- // If immediate persistence detected, write operations should be marked destructive
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"}
@@ -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",
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>",