@bryan-thompson/inspector-assessment-client 1.24.0 → 1.24.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.
@@ -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-CpSz2G0J.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-CauENw8a.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-CpSz2G0J.js";
1
+ import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-CauENw8a.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.24.0";
16323
+ const version$1 = "1.24.1";
16324
16324
  const packageJson = {
16325
16325
  name,
16326
16326
  version: version$1
@@ -45217,7 +45217,7 @@ const useTheme = () => {
45217
45217
  [theme, setThemeWithSideEffect]
45218
45218
  );
45219
45219
  };
45220
- const version = "1.24.0";
45220
+ const version = "1.24.1";
45221
45221
  var [createTooltipContext] = createContextScope("Tooltip", [
45222
45222
  createPopperScope
45223
45223
  ]);
@@ -48774,13 +48774,13 @@ const App = () => {
48774
48774
  ) });
48775
48775
  if (window.location.pathname === "/oauth/callback") {
48776
48776
  const OAuthCallback = React.lazy(
48777
- () => __vitePreload(() => import("./OAuthCallback-DNKtD7AZ.js"), true ? [] : void 0)
48777
+ () => __vitePreload(() => import("./OAuthCallback-CoDaMN6l.js"), true ? [] : void 0)
48778
48778
  );
48779
48779
  return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthCallback, { onConnect: onOAuthConnect }) });
48780
48780
  }
48781
48781
  if (window.location.pathname === "/oauth/callback/debug") {
48782
48782
  const OAuthDebugCallback = React.lazy(
48783
- () => __vitePreload(() => import("./OAuthDebugCallback-BbXkq3Wx.js"), true ? [] : void 0)
48783
+ () => __vitePreload(() => import("./OAuthDebugCallback-DVsgc4Jd.js"), true ? [] : void 0)
48784
48784
  );
48785
48785
  return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthDebugCallback, { onConnect: onOAuthDebugConnect }) });
48786
48786
  }
package/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-CpSz2G0J.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-CauENw8a.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-Df9Sx1jt.css">
10
10
  </head>
11
11
  <body>
@@ -15,11 +15,32 @@ import type { ProtocolConformanceAssessment } from "../../../lib/assessment/exte
15
15
  import { BaseAssessor } from "./BaseAssessor.js";
16
16
  import { AssessmentContext } from "../AssessmentOrchestrator.js";
17
17
  export declare class ProtocolConformanceAssessor extends BaseAssessor<ProtocolConformanceAssessment> {
18
+ /**
19
+ * Select representative tools for testing (first, middle, last for diversity)
20
+ */
21
+ private selectToolsForTesting;
22
+ /**
23
+ * Get MCP spec version from config or use default
24
+ */
25
+ private getSpecVersion;
26
+ /**
27
+ * Get base URL for MCP specification
28
+ */
29
+ private getSpecBaseUrl;
30
+ /**
31
+ * Get lifecycle spec URL
32
+ */
33
+ private getSpecLifecycleUrl;
34
+ /**
35
+ * Get tools spec URL
36
+ */
37
+ private getSpecToolsUrl;
18
38
  assess(context: AssessmentContext): Promise<ProtocolConformanceAssessment>;
19
39
  /**
20
40
  * Check 1: Error Response Format
21
41
  * Validates that error responses follow MCP protocol structure
22
42
  *
43
+ * Tests multiple tools (up to 3) for representative coverage.
23
44
  * Based on conformance's ToolsCallErrorScenario:
24
45
  * - isError flag must be true
25
46
  * - content must be an array
@@ -1 +1 @@
1
- {"version":3,"file":"ProtocolConformanceAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ProtocolConformanceAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EACV,6BAA6B,EAE9B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AA2B9D,qBAAa,2BAA4B,SAAQ,YAAY,CAAC,6BAA6B,CAAC;IACpF,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,6BAA6B,CAAC;IAqCzC;;;;;;;;OAQG;YACW,wBAAwB;IAoGtC;;;;;OAKG;YACW,uBAAuB;IAkGrC;;;;;;;;OAQG;YACW,4BAA4B;IAkD1C;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA6BjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmC3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CA2ChC"}
1
+ {"version":3,"file":"ProtocolConformanceAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ProtocolConformanceAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EACV,6BAA6B,EAE9B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAmB9D,qBAAa,2BAA4B,SAAQ,YAAY,CAAC,6BAA6B,CAAC;IAC1F;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAS7B;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAIjB,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,6BAA6B,CAAC;IAqCzC;;;;;;;;;OASG;YACW,wBAAwB;IAoHtC;;;;;OAKG;YACW,uBAAuB;IAkGrC;;;;;;;;OAQG;YACW,4BAA4B;IAkD1C;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA6BjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmC3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CA6ChC"}
@@ -12,13 +12,6 @@
12
12
  * @module assessment/modules/ProtocolConformanceAssessor
13
13
  */
14
14
  import { BaseAssessor } from "./BaseAssessor.js";
15
- // MCP specification references
16
- // NOTE: Update this URL when targeting a newer MCP spec version
17
- // See: https://modelcontextprotocol.io/specification for available versions
18
- const MCP_SPEC_VERSION = "2025-06-18";
19
- const MCP_SPEC_BASE = `https://modelcontextprotocol.io/specification/${MCP_SPEC_VERSION}`;
20
- const SPEC_LIFECYCLE = `${MCP_SPEC_BASE}/basic/lifecycle`;
21
- const SPEC_TOOLS = `${MCP_SPEC_BASE}/server/tools`;
22
15
  // Valid MCP content types
23
16
  const VALID_CONTENT_TYPES = [
24
17
  "text",
@@ -28,6 +21,39 @@ const VALID_CONTENT_TYPES = [
28
21
  "resource_link",
29
22
  ];
30
23
  export class ProtocolConformanceAssessor extends BaseAssessor {
24
+ /**
25
+ * Select representative tools for testing (first, middle, last for diversity)
26
+ */
27
+ selectToolsForTesting(tools, maxTools = 3) {
28
+ if (tools.length <= maxTools)
29
+ return tools;
30
+ const indices = [0, Math.floor(tools.length / 2), tools.length - 1];
31
+ return [...new Set(indices)].slice(0, maxTools).map((i) => tools[i]);
32
+ }
33
+ /**
34
+ * Get MCP spec version from config or use default
35
+ */
36
+ getSpecVersion() {
37
+ return this.config.mcpProtocolVersion || "2025-06";
38
+ }
39
+ /**
40
+ * Get base URL for MCP specification
41
+ */
42
+ getSpecBaseUrl() {
43
+ return `https://modelcontextprotocol.io/specification/${this.getSpecVersion()}`;
44
+ }
45
+ /**
46
+ * Get lifecycle spec URL
47
+ */
48
+ getSpecLifecycleUrl() {
49
+ return `${this.getSpecBaseUrl()}/basic/lifecycle`;
50
+ }
51
+ /**
52
+ * Get tools spec URL
53
+ */
54
+ getSpecToolsUrl() {
55
+ return `${this.getSpecBaseUrl()}/server/tools`;
56
+ }
31
57
  async assess(context) {
32
58
  this.logger.info("Starting protocol conformance assessment");
33
59
  // Run all protocol checks
@@ -60,96 +86,108 @@ export class ProtocolConformanceAssessor extends BaseAssessor {
60
86
  * Check 1: Error Response Format
61
87
  * Validates that error responses follow MCP protocol structure
62
88
  *
89
+ * Tests multiple tools (up to 3) for representative coverage.
63
90
  * Based on conformance's ToolsCallErrorScenario:
64
91
  * - isError flag must be true
65
92
  * - content must be an array
66
93
  * - content items must have type: "text" and text field
67
94
  */
68
95
  async checkErrorResponseFormat(context) {
69
- try {
70
- const testTool = context.tools[0];
71
- if (!testTool) {
72
- return {
73
- passed: false,
74
- confidence: "low",
75
- evidence: "No tools available to test error response format",
76
- specReference: SPEC_LIFECYCLE,
77
- warnings: ["Cannot validate error format without tools"],
78
- };
79
- }
80
- // Call with parameters designed to cause an error
81
- // (invalid param that doesn't match schema)
82
- const result = await this.executeWithTimeout(context.callTool(testTool.name, {
83
- __test_invalid_param__: "should_cause_error",
84
- }), this.config.testTimeout);
85
- // Validate MCP error response structure
86
- const contentArray = Array.isArray(result.content) ? result.content : [];
87
- const validations = {
88
- hasIsErrorFlag: result.isError === true,
89
- hasContentArray: Array.isArray(result.content),
90
- contentNotEmpty: contentArray.length > 0,
91
- firstContentHasType: contentArray[0]?.type !== undefined,
92
- firstContentIsTextOrResource: contentArray[0]?.type === "text" ||
93
- contentArray[0]?.type === "resource",
94
- hasErrorMessage: typeof contentArray[0]?.text === "string" &&
95
- contentArray[0].text.length > 0,
96
- };
97
- const passedValidations = Object.values(validations).filter((v) => v);
98
- const allPassed = passedValidations.length === Object.keys(validations).length;
99
- // If result is not an error, that's okay - the tool might have accepted the params
100
- // In that case, we can't validate error format, but it's not a failure
101
- if (!result.isError && contentArray.length > 0) {
102
- return {
103
- passed: true,
104
- confidence: "medium",
105
- evidence: "Tool did not return an error with invalid params (may have accepted them). Content structure is valid.",
106
- specReference: SPEC_LIFECYCLE,
107
- details: {
108
- note: "Tool accepted test params without error - cannot validate error format",
109
- contentStructure: contentArray.map((c) => ({
110
- type: c.type,
111
- })),
112
- },
113
- };
114
- }
96
+ const testTools = this.selectToolsForTesting(context.tools, 3);
97
+ if (testTools.length === 0) {
115
98
  return {
116
- passed: allPassed,
117
- confidence: allPassed ? "high" : "medium",
118
- evidence: `${passedValidations.length}/${Object.keys(validations).length} error format validations passed`,
119
- specReference: SPEC_LIFECYCLE,
120
- details: {
121
- validations,
122
- sampleResponse: {
123
- isError: result.isError,
124
- contentLength: contentArray.length,
125
- firstContentType: contentArray[0]?.type,
126
- },
127
- },
128
- warnings: allPassed
129
- ? undefined
130
- : [
131
- "Error response does not fully comply with MCP protocol format",
132
- "Ensure errors have isError: true and content array with text type",
133
- ],
99
+ passed: false,
100
+ confidence: "low",
101
+ evidence: "No tools available to test error response format",
102
+ specReference: this.getSpecLifecycleUrl(),
103
+ warnings: ["Cannot validate error format without tools"],
134
104
  };
135
105
  }
136
- catch (error) {
137
- // If the call threw an exception instead of returning an error response,
138
- // that's also a protocol violation (but might be SDK-level)
139
- return {
140
- passed: false,
141
- confidence: "medium",
142
- evidence: "Tool threw exception instead of returning error response",
143
- specReference: SPEC_LIFECYCLE,
144
- details: {
106
+ // Test each selected tool and collect results
107
+ const results = [];
108
+ for (const testTool of testTools) {
109
+ try {
110
+ // Call with parameters designed to cause an error
111
+ const result = await this.executeWithTimeout(context.callTool(testTool.name, {
112
+ __test_invalid_param__: "should_cause_error",
113
+ }), this.config.testTimeout);
114
+ // Validate MCP error response structure
115
+ const contentArray = Array.isArray(result.content)
116
+ ? result.content
117
+ : [];
118
+ const validations = {
119
+ hasIsErrorFlag: result.isError === true,
120
+ hasContentArray: Array.isArray(result.content),
121
+ contentNotEmpty: contentArray.length > 0,
122
+ firstContentHasType: contentArray[0]?.type !== undefined,
123
+ firstContentIsTextOrResource: contentArray[0]?.type === "text" ||
124
+ contentArray[0]?.type === "resource",
125
+ hasErrorMessage: typeof contentArray[0]?.text === "string" &&
126
+ contentArray[0].text.length > 0,
127
+ };
128
+ // Tool did not return error - might have accepted params
129
+ if (!result.isError && contentArray.length > 0) {
130
+ results.push({
131
+ toolName: testTool.name,
132
+ passed: true,
133
+ isErrorResponse: false,
134
+ validations,
135
+ });
136
+ }
137
+ else {
138
+ const passedValidations = Object.values(validations).filter((v) => v);
139
+ const allPassed = passedValidations.length === Object.keys(validations).length;
140
+ results.push({
141
+ toolName: testTool.name,
142
+ passed: allPassed,
143
+ isErrorResponse: true,
144
+ validations,
145
+ });
146
+ }
147
+ }
148
+ catch (error) {
149
+ // Tool threw exception instead of returning error response
150
+ results.push({
151
+ toolName: testTool.name,
152
+ passed: false,
153
+ isErrorResponse: false,
145
154
  error: error instanceof Error ? error.message : String(error),
146
- },
147
- warnings: [
148
- "Tools should return error responses, not throw exceptions",
149
- "This may be caused by transport-level issues or SDK handling",
150
- ],
151
- };
155
+ });
156
+ }
157
+ }
158
+ // Aggregate results
159
+ const errorResponseResults = results.filter((r) => r.isErrorResponse);
160
+ const passedCount = results.filter((r) => r.passed).length;
161
+ const allPassed = passedCount === results.length;
162
+ // Determine confidence based on error response coverage
163
+ let confidence;
164
+ if (errorResponseResults.length === 0) {
165
+ // No tools returned errors - all accepted invalid params
166
+ confidence = "medium";
152
167
  }
168
+ else if (allPassed) {
169
+ confidence = "high";
170
+ }
171
+ else {
172
+ confidence = "medium";
173
+ }
174
+ return {
175
+ passed: allPassed,
176
+ confidence,
177
+ evidence: `Tested ${results.length} tool(s): ${passedCount}/${results.length} passed error format validation`,
178
+ specReference: this.getSpecLifecycleUrl(),
179
+ details: {
180
+ toolResults: results,
181
+ testedToolCount: results.length,
182
+ errorResponseCount: errorResponseResults.length,
183
+ },
184
+ warnings: allPassed
185
+ ? undefined
186
+ : [
187
+ "Error response format issues detected in some tools",
188
+ "Ensure all errors have isError: true and content array with text type",
189
+ ],
190
+ };
153
191
  }
154
192
  /**
155
193
  * Check 2: Content Type Support
@@ -165,7 +203,7 @@ export class ProtocolConformanceAssessor extends BaseAssessor {
165
203
  passed: false,
166
204
  confidence: "low",
167
205
  evidence: "No tools available to test content types",
168
- specReference: SPEC_TOOLS,
206
+ specReference: this.getSpecToolsUrl(),
169
207
  };
170
208
  }
171
209
  // Check if tool has required params - if so, we can't easily test
@@ -178,7 +216,7 @@ export class ProtocolConformanceAssessor extends BaseAssessor {
178
216
  passed: true,
179
217
  confidence: "low",
180
218
  evidence: "Cannot test content types without knowing valid parameters - tool has required params",
181
- specReference: SPEC_TOOLS,
219
+ specReference: this.getSpecToolsUrl(),
182
220
  warnings: [
183
221
  "Content type validation requires valid tool parameters",
184
222
  "Consider adding a tool without required params for protocol testing",
@@ -204,7 +242,7 @@ export class ProtocolConformanceAssessor extends BaseAssessor {
204
242
  passed: allPassed,
205
243
  confidence: allPassed ? "high" : "medium",
206
244
  evidence: `${passedValidations.length}/${Object.keys(validations).length} content type checks passed`,
207
- specReference: SPEC_TOOLS,
245
+ specReference: this.getSpecToolsUrl(),
208
246
  details: {
209
247
  validations,
210
248
  detectedContentTypes: detectedTypes,
@@ -220,7 +258,7 @@ export class ProtocolConformanceAssessor extends BaseAssessor {
220
258
  passed: false,
221
259
  confidence: "medium",
222
260
  evidence: "Could not test content types due to error",
223
- specReference: SPEC_TOOLS,
261
+ specReference: this.getSpecToolsUrl(),
224
262
  details: {
225
263
  error: error instanceof Error ? error.message : String(error),
226
264
  },
@@ -254,7 +292,7 @@ export class ProtocolConformanceAssessor extends BaseAssessor {
254
292
  passed: hasMinimumInfo,
255
293
  confidence: allPassed ? "high" : "medium",
256
294
  evidence: `${passedValidations.length}/${Object.keys(validations).length} initialization checks passed`,
257
- specReference: SPEC_LIFECYCLE,
295
+ specReference: this.getSpecLifecycleUrl(),
258
296
  details: {
259
297
  validations,
260
298
  serverInfo: {
@@ -351,7 +389,7 @@ export class ProtocolConformanceAssessor extends BaseAssessor {
351
389
  recommendations.push("Protocol conformance is good. Consider testing with official @modelcontextprotocol/conformance suite for comprehensive validation.");
352
390
  }
353
391
  else {
354
- recommendations.push(`Review MCP specification: ${MCP_SPEC_BASE}/`);
392
+ recommendations.push(`Review MCP specification: ${this.getSpecBaseUrl()}/`);
355
393
  }
356
394
  return recommendations;
357
395
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bryan-thompson/inspector-assessment-client",
3
- "version": "1.24.0",
3
+ "version": "1.24.2",
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>",