@bryan-thompson/inspector-assessment 1.6.0 → 1.7.0

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.
Files changed (76) hide show
  1. package/cli/build/assess-full.js +528 -0
  2. package/cli/build/assess-security.js +342 -0
  3. package/client/dist/assets/{OAuthCallback-ZcXdfhZQ.js → OAuthCallback-Xo9zS7pv.js} +1 -1
  4. package/client/dist/assets/{OAuthDebugCallback-xt1SlIHS.js → OAuthDebugCallback-CaIey8K_.js} +1 -1
  5. package/client/dist/assets/{index-B3lTiDVe.js → index-nCPw6E-c.js} +4 -4
  6. package/client/dist/index.html +1 -1
  7. package/client/lib/lib/assessmentTypes.d.ts +670 -0
  8. package/client/lib/lib/assessmentTypes.d.ts.map +1 -0
  9. package/client/lib/lib/assessmentTypes.js +220 -0
  10. package/client/lib/lib/aupPatterns.d.ts +63 -0
  11. package/client/lib/lib/aupPatterns.d.ts.map +1 -0
  12. package/client/lib/lib/aupPatterns.js +344 -0
  13. package/client/lib/lib/prohibitedLibraries.d.ts +76 -0
  14. package/client/lib/lib/prohibitedLibraries.d.ts.map +1 -0
  15. package/client/lib/lib/prohibitedLibraries.js +364 -0
  16. package/client/lib/lib/securityPatterns.d.ts +64 -0
  17. package/client/lib/lib/securityPatterns.d.ts.map +1 -0
  18. package/client/lib/lib/securityPatterns.js +453 -0
  19. package/client/lib/services/assessment/AssessmentOrchestrator.d.ts +88 -0
  20. package/client/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -0
  21. package/client/lib/services/assessment/AssessmentOrchestrator.js +418 -0
  22. package/client/lib/services/assessment/ResponseValidator.d.ts +69 -0
  23. package/client/lib/services/assessment/ResponseValidator.d.ts.map +1 -0
  24. package/client/lib/services/assessment/ResponseValidator.js +1038 -0
  25. package/client/lib/services/assessment/TestDataGenerator.d.ts +86 -0
  26. package/client/lib/services/assessment/TestDataGenerator.d.ts.map +1 -0
  27. package/client/lib/services/assessment/TestDataGenerator.js +669 -0
  28. package/client/lib/services/assessment/TestScenarioEngine.d.ts +91 -0
  29. package/client/lib/services/assessment/TestScenarioEngine.d.ts.map +1 -0
  30. package/client/lib/services/assessment/TestScenarioEngine.js +505 -0
  31. package/client/lib/services/assessment/ToolClassifier.d.ts +61 -0
  32. package/client/lib/services/assessment/ToolClassifier.d.ts.map +1 -0
  33. package/client/lib/services/assessment/ToolClassifier.js +349 -0
  34. package/client/lib/services/assessment/lib/claudeCodeBridge.d.ts +160 -0
  35. package/client/lib/services/assessment/lib/claudeCodeBridge.d.ts.map +1 -0
  36. package/client/lib/services/assessment/lib/claudeCodeBridge.js +357 -0
  37. package/client/lib/services/assessment/modules/AUPComplianceAssessor.d.ts +100 -0
  38. package/client/lib/services/assessment/modules/AUPComplianceAssessor.d.ts.map +1 -0
  39. package/client/lib/services/assessment/modules/AUPComplianceAssessor.js +474 -0
  40. package/client/lib/services/assessment/modules/BaseAssessor.d.ts +71 -0
  41. package/client/lib/services/assessment/modules/BaseAssessor.d.ts.map +1 -0
  42. package/client/lib/services/assessment/modules/BaseAssessor.js +171 -0
  43. package/client/lib/services/assessment/modules/DocumentationAssessor.d.ts +45 -0
  44. package/client/lib/services/assessment/modules/DocumentationAssessor.d.ts.map +1 -0
  45. package/client/lib/services/assessment/modules/DocumentationAssessor.js +355 -0
  46. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts +25 -0
  47. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -0
  48. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.js +564 -0
  49. package/client/lib/services/assessment/modules/FunctionalityAssessor.d.ts +20 -0
  50. package/client/lib/services/assessment/modules/FunctionalityAssessor.d.ts.map +1 -0
  51. package/client/lib/services/assessment/modules/FunctionalityAssessor.js +253 -0
  52. package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts +70 -0
  53. package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts.map +1 -0
  54. package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.js +508 -0
  55. package/client/lib/services/assessment/modules/ManifestValidationAssessor.d.ts +70 -0
  56. package/client/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -0
  57. package/client/lib/services/assessment/modules/ManifestValidationAssessor.js +430 -0
  58. package/client/lib/services/assessment/modules/PortabilityAssessor.d.ts +43 -0
  59. package/client/lib/services/assessment/modules/PortabilityAssessor.d.ts.map +1 -0
  60. package/client/lib/services/assessment/modules/PortabilityAssessor.js +347 -0
  61. package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts +41 -0
  62. package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts.map +1 -0
  63. package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.js +256 -0
  64. package/client/lib/services/assessment/modules/SecurityAssessor.d.ts +176 -0
  65. package/client/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -0
  66. package/client/lib/services/assessment/modules/SecurityAssessor.js +1333 -0
  67. package/client/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts +96 -0
  68. package/client/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -0
  69. package/client/lib/services/assessment/modules/ToolAnnotationAssessor.js +593 -0
  70. package/client/lib/services/assessment/modules/UsabilityAssessor.d.ts +21 -0
  71. package/client/lib/services/assessment/modules/UsabilityAssessor.d.ts.map +1 -0
  72. package/client/lib/services/assessment/modules/UsabilityAssessor.js +241 -0
  73. package/client/lib/services/assessment/modules/index.d.ts +33 -0
  74. package/client/lib/services/assessment/modules/index.d.ts.map +1 -0
  75. package/client/lib/services/assessment/modules/index.js +35 -0
  76. package/package.json +5 -2
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Tool Annotation Assessor
3
+ * Verifies MCP tools have proper annotations per Policy #17
4
+ *
5
+ * Checks:
6
+ * - readOnlyHint presence and accuracy
7
+ * - destructiveHint presence and accuracy
8
+ * - Tool behavior inference from name patterns
9
+ * - Annotation misalignment detection
10
+ *
11
+ * Reference: Anthropic MCP Directory Policy #17
12
+ */
13
+ import { BaseAssessor } from "./BaseAssessor.js";
14
+ import { AssessmentContext } from "../AssessmentOrchestrator.js";
15
+ import type { ToolAnnotationAssessment, ToolAnnotationResult } from "../../../lib/assessmentTypes.js";
16
+ import type { ClaudeCodeBridge } from "../lib/claudeCodeBridge.js";
17
+ /**
18
+ * Enhanced tool annotation result with Claude inference
19
+ */
20
+ export interface EnhancedToolAnnotationResult extends ToolAnnotationResult {
21
+ claudeInference?: {
22
+ expectedReadOnly: boolean;
23
+ expectedDestructive: boolean;
24
+ confidence: number;
25
+ reasoning: string;
26
+ suggestedAnnotations: {
27
+ readOnlyHint?: boolean;
28
+ destructiveHint?: boolean;
29
+ idempotentHint?: boolean;
30
+ };
31
+ misalignmentDetected: boolean;
32
+ misalignmentDetails?: string;
33
+ source: "claude-inferred" | "pattern-based";
34
+ };
35
+ }
36
+ /**
37
+ * Enhanced assessment with Claude integration
38
+ */
39
+ export interface EnhancedToolAnnotationAssessment extends ToolAnnotationAssessment {
40
+ toolResults: EnhancedToolAnnotationResult[];
41
+ claudeEnhanced: boolean;
42
+ highConfidenceMisalignments: EnhancedToolAnnotationResult[];
43
+ }
44
+ export declare class ToolAnnotationAssessor extends BaseAssessor {
45
+ private claudeBridge?;
46
+ /**
47
+ * Set Claude Code Bridge for enhanced behavior inference
48
+ */
49
+ setClaudeBridge(bridge: ClaudeCodeBridge): void;
50
+ /**
51
+ * Check if Claude enhancement is available
52
+ */
53
+ isClaudeEnabled(): boolean;
54
+ /**
55
+ * Run tool annotation assessment
56
+ */
57
+ assess(context: AssessmentContext): Promise<ToolAnnotationAssessment | EnhancedToolAnnotationAssessment>;
58
+ /**
59
+ * Enhance tool assessment with Claude inference
60
+ */
61
+ private enhanceWithClaudeInference;
62
+ /**
63
+ * Generate enhanced explanation with Claude analysis
64
+ */
65
+ private generateEnhancedExplanation;
66
+ /**
67
+ * Generate enhanced recommendations with Claude analysis
68
+ */
69
+ private generateEnhancedRecommendations;
70
+ /**
71
+ * Assess a single tool's annotations
72
+ */
73
+ private assessTool;
74
+ /**
75
+ * Extract annotations from a tool
76
+ * MCP SDK may have annotations in different locations
77
+ */
78
+ private extractAnnotations;
79
+ /**
80
+ * Infer expected behavior from tool name and description
81
+ */
82
+ private inferBehavior;
83
+ /**
84
+ * Determine overall status
85
+ */
86
+ private determineAnnotationStatus;
87
+ /**
88
+ * Generate explanation
89
+ */
90
+ private generateExplanation;
91
+ /**
92
+ * Generate recommendations
93
+ */
94
+ private generateRecommendations;
95
+ }
96
+ //# sourceMappingURL=ToolAnnotationAssessor.d.ts.map
@@ -0,0 +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,EAErB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE;;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;AAwED,qBAAa,sBAAuB,SAAQ,YAAY;IACtD,OAAO,CAAC,YAAY,CAAC,CAAmB;IAExC;;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;IAqIvE;;OAEG;YACW,0BAA0B;IA+IxC;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAiCnC;;OAEG;IACH,OAAO,CAAC,+BAA+B;IAoFvC;;OAEG;IACH,OAAO,CAAC,UAAU;IAqElB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAyC1B;;OAEG;IACH,OAAO,CAAC,aAAa;IA0ErB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAsCjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmC3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CA2ChC"}
@@ -0,0 +1,593 @@
1
+ /**
2
+ * Tool Annotation Assessor
3
+ * Verifies MCP tools have proper annotations per Policy #17
4
+ *
5
+ * Checks:
6
+ * - readOnlyHint presence and accuracy
7
+ * - destructiveHint presence and accuracy
8
+ * - Tool behavior inference from name patterns
9
+ * - Annotation misalignment detection
10
+ *
11
+ * Reference: Anthropic MCP Directory Policy #17
12
+ */
13
+ import { BaseAssessor } from "./BaseAssessor.js";
14
+ /**
15
+ * Patterns for inferring expected tool behavior from name
16
+ */
17
+ const READ_ONLY_PATTERNS = [
18
+ /^get[_-]?/i,
19
+ /^list[_-]?/i,
20
+ /^fetch[_-]?/i,
21
+ /^read[_-]?/i,
22
+ /^query[_-]?/i,
23
+ /^search[_-]?/i,
24
+ /^find[_-]?/i,
25
+ /^show[_-]?/i,
26
+ /^view[_-]?/i,
27
+ /^describe[_-]?/i,
28
+ /^check[_-]?/i,
29
+ /^verify[_-]?/i,
30
+ /^validate[_-]?/i,
31
+ /^count[_-]?/i,
32
+ /^status[_-]?/i,
33
+ /^info[_-]?/i,
34
+ /^lookup[_-]?/i,
35
+ /^browse[_-]?/i,
36
+ /^preview[_-]?/i,
37
+ /^download[_-]?/i, // Downloads but doesn't modify server state
38
+ ];
39
+ const DESTRUCTIVE_PATTERNS = [
40
+ /^delete[_-]?/i,
41
+ /^remove[_-]?/i,
42
+ /^destroy[_-]?/i,
43
+ /^drop[_-]?/i,
44
+ /^purge[_-]?/i,
45
+ /^clear[_-]?/i,
46
+ /^wipe[_-]?/i,
47
+ /^erase[_-]?/i,
48
+ /^reset[_-]?/i,
49
+ /^truncate[_-]?/i,
50
+ /^revoke[_-]?/i,
51
+ /^terminate[_-]?/i,
52
+ /^cancel[_-]?/i,
53
+ /^kill[_-]?/i,
54
+ /^force[_-]?/i,
55
+ ];
56
+ const WRITE_PATTERNS = [
57
+ /^create[_-]?/i,
58
+ /^add[_-]?/i,
59
+ /^insert[_-]?/i,
60
+ /^update[_-]?/i,
61
+ /^modify[_-]?/i,
62
+ /^edit[_-]?/i,
63
+ /^change[_-]?/i,
64
+ /^set[_-]?/i,
65
+ /^put[_-]?/i,
66
+ /^patch[_-]?/i,
67
+ /^post[_-]?/i,
68
+ /^write[_-]?/i,
69
+ /^save[_-]?/i,
70
+ /^upload[_-]?/i,
71
+ /^send[_-]?/i,
72
+ /^submit[_-]?/i,
73
+ /^publish[_-]?/i,
74
+ /^enable[_-]?/i,
75
+ /^disable[_-]?/i,
76
+ /^start[_-]?/i,
77
+ /^stop[_-]?/i,
78
+ /^run[_-]?/i,
79
+ /^execute[_-]?/i,
80
+ ];
81
+ export class ToolAnnotationAssessor extends BaseAssessor {
82
+ claudeBridge;
83
+ /**
84
+ * Set Claude Code Bridge for enhanced behavior inference
85
+ */
86
+ setClaudeBridge(bridge) {
87
+ this.claudeBridge = bridge;
88
+ this.log("Claude Code Bridge enabled for behavior inference");
89
+ }
90
+ /**
91
+ * Check if Claude enhancement is available
92
+ */
93
+ isClaudeEnabled() {
94
+ return (this.claudeBridge !== undefined &&
95
+ this.claudeBridge.isFeatureEnabled("annotationInference"));
96
+ }
97
+ /**
98
+ * Run tool annotation assessment
99
+ */
100
+ async assess(context) {
101
+ this.log("Starting tool annotation assessment");
102
+ this.testCount = 0;
103
+ const toolResults = [];
104
+ let annotatedCount = 0;
105
+ let missingAnnotationsCount = 0;
106
+ let misalignedAnnotationsCount = 0;
107
+ const useClaudeInference = this.isClaudeEnabled();
108
+ if (useClaudeInference) {
109
+ this.log("Claude Code integration enabled - using semantic behavior inference");
110
+ }
111
+ for (const tool of context.tools) {
112
+ this.testCount++;
113
+ const result = this.assessTool(tool);
114
+ // Enhance with Claude inference if available
115
+ if (useClaudeInference) {
116
+ const enhancedResult = await this.enhanceWithClaudeInference(tool, result);
117
+ toolResults.push(enhancedResult);
118
+ // Count based on Claude analysis if high confidence
119
+ if (enhancedResult.claudeInference &&
120
+ enhancedResult.claudeInference.confidence >= 70 &&
121
+ enhancedResult.claudeInference.misalignmentDetected) {
122
+ misalignedAnnotationsCount++;
123
+ }
124
+ else if (result.issues.some((i) => i.includes("misaligned"))) {
125
+ misalignedAnnotationsCount++;
126
+ }
127
+ }
128
+ else {
129
+ // Standard pattern-based result
130
+ const inferredBehavior = result.inferredBehavior ?? {
131
+ expectedReadOnly: false,
132
+ expectedDestructive: false,
133
+ reason: "No behavior inference available",
134
+ };
135
+ toolResults.push({
136
+ ...result,
137
+ claudeInference: {
138
+ expectedReadOnly: inferredBehavior.expectedReadOnly,
139
+ expectedDestructive: inferredBehavior.expectedDestructive,
140
+ confidence: 50, // Lower confidence for pattern-based
141
+ reasoning: inferredBehavior.reason,
142
+ suggestedAnnotations: {
143
+ readOnlyHint: inferredBehavior.expectedReadOnly,
144
+ destructiveHint: inferredBehavior.expectedDestructive,
145
+ },
146
+ misalignmentDetected: result.issues.some((i) => i.includes("misaligned")),
147
+ source: "pattern-based",
148
+ },
149
+ });
150
+ if (result.issues.some((i) => i.includes("misaligned"))) {
151
+ misalignedAnnotationsCount++;
152
+ }
153
+ }
154
+ if (toolResults[toolResults.length - 1].hasAnnotations) {
155
+ annotatedCount++;
156
+ }
157
+ else {
158
+ missingAnnotationsCount++;
159
+ }
160
+ }
161
+ const status = this.determineAnnotationStatus(toolResults, context.tools.length);
162
+ const explanation = this.generateExplanation(annotatedCount, missingAnnotationsCount, misalignedAnnotationsCount, context.tools.length);
163
+ const recommendations = this.generateRecommendations(toolResults);
164
+ this.log(`Assessment complete: ${annotatedCount}/${context.tools.length} tools annotated, ${misalignedAnnotationsCount} misaligned`);
165
+ // Return enhanced assessment if Claude was used
166
+ if (useClaudeInference) {
167
+ const highConfidenceMisalignments = toolResults.filter((r) => r.claudeInference &&
168
+ r.claudeInference.confidence >= 70 &&
169
+ r.claudeInference.misalignmentDetected);
170
+ this.log(`Claude inference found ${highConfidenceMisalignments.length} high-confidence misalignments`);
171
+ return {
172
+ toolResults,
173
+ annotatedCount,
174
+ missingAnnotationsCount,
175
+ misalignedAnnotationsCount,
176
+ status,
177
+ explanation: this.generateEnhancedExplanation(annotatedCount, missingAnnotationsCount, highConfidenceMisalignments.length, context.tools.length),
178
+ recommendations: this.generateEnhancedRecommendations(toolResults),
179
+ claudeEnhanced: true,
180
+ highConfidenceMisalignments,
181
+ };
182
+ }
183
+ return {
184
+ toolResults,
185
+ annotatedCount,
186
+ missingAnnotationsCount,
187
+ misalignedAnnotationsCount,
188
+ status,
189
+ explanation,
190
+ recommendations,
191
+ };
192
+ }
193
+ /**
194
+ * Enhance tool assessment with Claude inference
195
+ */
196
+ async enhanceWithClaudeInference(tool, baseResult) {
197
+ const inferredBehavior = baseResult.inferredBehavior ?? {
198
+ expectedReadOnly: false,
199
+ expectedDestructive: false,
200
+ reason: "No behavior inference available",
201
+ };
202
+ if (!this.claudeBridge) {
203
+ return {
204
+ ...baseResult,
205
+ claudeInference: {
206
+ expectedReadOnly: inferredBehavior.expectedReadOnly,
207
+ expectedDestructive: inferredBehavior.expectedDestructive,
208
+ confidence: 50,
209
+ reasoning: inferredBehavior.reason,
210
+ suggestedAnnotations: {
211
+ readOnlyHint: inferredBehavior.expectedReadOnly,
212
+ destructiveHint: inferredBehavior.expectedDestructive,
213
+ },
214
+ misalignmentDetected: baseResult.issues.some((i) => i.includes("misaligned")),
215
+ source: "pattern-based",
216
+ },
217
+ };
218
+ }
219
+ try {
220
+ const currentAnnotations = baseResult.annotations
221
+ ? {
222
+ readOnlyHint: baseResult.annotations.readOnlyHint,
223
+ destructiveHint: baseResult.annotations.destructiveHint,
224
+ }
225
+ : undefined;
226
+ const inference = await this.claudeBridge.inferToolBehavior(tool, currentAnnotations);
227
+ // Handle null result (Claude unavailable or error)
228
+ if (!inference) {
229
+ return {
230
+ ...baseResult,
231
+ claudeInference: {
232
+ expectedReadOnly: inferredBehavior.expectedReadOnly,
233
+ expectedDestructive: inferredBehavior.expectedDestructive,
234
+ confidence: 0,
235
+ reasoning: "Claude inference unavailable. Using pattern-based analysis.",
236
+ suggestedAnnotations: {},
237
+ misalignmentDetected: false,
238
+ misalignmentDetails: undefined,
239
+ source: "pattern-based",
240
+ },
241
+ };
242
+ }
243
+ // Merge Claude inference with pattern-based findings
244
+ const updatedIssues = [...baseResult.issues];
245
+ const updatedRecommendations = [...baseResult.recommendations];
246
+ // Add Claude-detected misalignment if high confidence
247
+ if (inference.misalignmentDetected && inference.confidence >= 70) {
248
+ const misalignmentMsg = inference.misalignmentDetails
249
+ ? `Claude analysis (${inference.confidence}% confidence): ${inference.misalignmentDetails}`
250
+ : `Claude analysis detected annotation misalignment with ${inference.confidence}% confidence`;
251
+ if (!updatedIssues.some((i) => i.includes("Claude analysis"))) {
252
+ updatedIssues.push(misalignmentMsg);
253
+ }
254
+ // Add specific recommendations based on Claude inference
255
+ if (inference.suggestedAnnotations) {
256
+ const { readOnlyHint, destructiveHint, idempotentHint } = inference.suggestedAnnotations;
257
+ if (readOnlyHint !== undefined &&
258
+ readOnlyHint !== baseResult.annotations?.readOnlyHint) {
259
+ updatedRecommendations.push(`Claude suggests: Set readOnlyHint=${readOnlyHint} for ${tool.name}`);
260
+ }
261
+ if (destructiveHint !== undefined &&
262
+ destructiveHint !== baseResult.annotations?.destructiveHint) {
263
+ updatedRecommendations.push(`Claude suggests: Set destructiveHint=${destructiveHint} for ${tool.name}`);
264
+ }
265
+ if (idempotentHint !== undefined) {
266
+ updatedRecommendations.push(`Claude suggests: Consider adding idempotentHint=${idempotentHint} for ${tool.name}`);
267
+ }
268
+ }
269
+ }
270
+ return {
271
+ ...baseResult,
272
+ issues: updatedIssues,
273
+ recommendations: updatedRecommendations,
274
+ claudeInference: {
275
+ expectedReadOnly: inference.expectedReadOnly,
276
+ expectedDestructive: inference.expectedDestructive,
277
+ confidence: inference.confidence,
278
+ reasoning: inference.reasoning,
279
+ suggestedAnnotations: inference.suggestedAnnotations,
280
+ misalignmentDetected: inference.misalignmentDetected,
281
+ misalignmentDetails: inference.misalignmentDetails,
282
+ source: "claude-inferred",
283
+ },
284
+ };
285
+ }
286
+ catch (error) {
287
+ this.logError(`Claude inference failed for ${tool.name}`, error);
288
+ // Fall back to pattern-based (use inferredBehavior from top of function)
289
+ return {
290
+ ...baseResult,
291
+ claudeInference: {
292
+ expectedReadOnly: inferredBehavior.expectedReadOnly,
293
+ expectedDestructive: inferredBehavior.expectedDestructive,
294
+ confidence: 50,
295
+ reasoning: `Claude inference failed, using pattern-based: ${inferredBehavior.reason}`,
296
+ suggestedAnnotations: {
297
+ readOnlyHint: inferredBehavior.expectedReadOnly,
298
+ destructiveHint: inferredBehavior.expectedDestructive,
299
+ },
300
+ misalignmentDetected: baseResult.issues.some((i) => i.includes("misaligned")),
301
+ source: "pattern-based",
302
+ },
303
+ };
304
+ }
305
+ }
306
+ /**
307
+ * Generate enhanced explanation with Claude analysis
308
+ */
309
+ generateEnhancedExplanation(annotatedCount, missingCount, highConfidenceMisalignments, totalTools) {
310
+ const parts = [];
311
+ if (totalTools === 0) {
312
+ return "No tools found to assess for annotations.";
313
+ }
314
+ parts.push(`Tool annotation coverage: ${annotatedCount}/${totalTools} tools have annotations.`);
315
+ if (missingCount > 0) {
316
+ parts.push(`${missingCount} tool(s) are missing required annotations (readOnlyHint, destructiveHint).`);
317
+ }
318
+ if (highConfidenceMisalignments > 0) {
319
+ parts.push(`Claude analysis identified ${highConfidenceMisalignments} high-confidence annotation misalignment(s).`);
320
+ }
321
+ parts.push("Analysis enhanced with Claude semantic behavior inference.");
322
+ return parts.join(" ");
323
+ }
324
+ /**
325
+ * Generate enhanced recommendations with Claude analysis
326
+ */
327
+ generateEnhancedRecommendations(results) {
328
+ const recommendations = [];
329
+ // Prioritize Claude high-confidence misalignments
330
+ const claudeMisalignments = results.filter((r) => r.claudeInference &&
331
+ r.claudeInference.source === "claude-inferred" &&
332
+ r.claudeInference.confidence >= 70 &&
333
+ r.claudeInference.misalignmentDetected);
334
+ if (claudeMisalignments.length > 0) {
335
+ recommendations.push("HIGH CONFIDENCE: Claude analysis identified the following annotation issues:");
336
+ for (const result of claudeMisalignments.slice(0, 5)) {
337
+ if (result.claudeInference) {
338
+ recommendations.push(` - ${result.toolName}: ${result.claudeInference.reasoning}`);
339
+ }
340
+ }
341
+ }
342
+ // Collect Claude suggestions
343
+ const claudeSuggestions = results
344
+ .filter((r) => r.claudeInference &&
345
+ r.claudeInference.source === "claude-inferred" &&
346
+ r.claudeInference.confidence >= 60)
347
+ .flatMap((r) => r.recommendations.filter((rec) => rec.includes("Claude")));
348
+ if (claudeSuggestions.length > 0) {
349
+ recommendations.push(...claudeSuggestions.slice(0, 5));
350
+ }
351
+ // Add pattern-based recommendations for remaining tools
352
+ const patternRecs = new Set();
353
+ for (const result of results) {
354
+ for (const rec of result.recommendations) {
355
+ if (!rec.includes("Claude")) {
356
+ patternRecs.add(rec);
357
+ }
358
+ }
359
+ }
360
+ const destructiveRecs = Array.from(patternRecs).filter((r) => r.includes("destructive"));
361
+ const otherRecs = Array.from(patternRecs).filter((r) => !r.includes("destructive"));
362
+ if (destructiveRecs.length > 0) {
363
+ recommendations.push("PRIORITY: Potential destructive tools without proper hints:");
364
+ recommendations.push(...destructiveRecs.slice(0, 3));
365
+ }
366
+ if (otherRecs.length > 0 && recommendations.length < 10) {
367
+ recommendations.push(...otherRecs.slice(0, 3));
368
+ }
369
+ if (recommendations.length === 0) {
370
+ recommendations.push("All tools have proper annotations. No action required.");
371
+ }
372
+ else {
373
+ recommendations.push("Reference: MCP Directory Policy #17 requires tools to have readOnlyHint and destructiveHint annotations.");
374
+ }
375
+ return recommendations;
376
+ }
377
+ /**
378
+ * Assess a single tool's annotations
379
+ */
380
+ assessTool(tool) {
381
+ const issues = [];
382
+ const recommendations = [];
383
+ // Extract annotations from tool
384
+ const annotations = this.extractAnnotations(tool);
385
+ const hasAnnotations = annotations.readOnlyHint !== undefined ||
386
+ annotations.destructiveHint !== undefined;
387
+ // Infer expected behavior from tool name
388
+ const inferredBehavior = this.inferBehavior(tool.name, tool.description);
389
+ // Check for missing annotations
390
+ if (!hasAnnotations) {
391
+ issues.push("Missing tool annotations (readOnlyHint, destructiveHint)");
392
+ recommendations.push(`Add annotations to ${tool.name}: readOnlyHint=${inferredBehavior.expectedReadOnly}, destructiveHint=${inferredBehavior.expectedDestructive}`);
393
+ }
394
+ else {
395
+ // Check for misaligned annotations
396
+ if (annotations.readOnlyHint !== undefined &&
397
+ annotations.readOnlyHint !== inferredBehavior.expectedReadOnly) {
398
+ issues.push(`Potentially misaligned readOnlyHint: set to ${annotations.readOnlyHint}, expected ${inferredBehavior.expectedReadOnly} based on tool name pattern`);
399
+ recommendations.push(`Verify readOnlyHint for ${tool.name}: currently ${annotations.readOnlyHint}, tool name suggests ${inferredBehavior.expectedReadOnly}`);
400
+ }
401
+ if (annotations.destructiveHint !== undefined &&
402
+ annotations.destructiveHint !== inferredBehavior.expectedDestructive) {
403
+ issues.push(`Potentially misaligned destructiveHint: set to ${annotations.destructiveHint}, expected ${inferredBehavior.expectedDestructive} based on tool name pattern`);
404
+ recommendations.push(`Verify destructiveHint for ${tool.name}: currently ${annotations.destructiveHint}, tool name suggests ${inferredBehavior.expectedDestructive}`);
405
+ }
406
+ }
407
+ // Check for destructive tools without explicit hint
408
+ if (inferredBehavior.expectedDestructive &&
409
+ annotations.destructiveHint !== true) {
410
+ issues.push("Tool appears destructive but destructiveHint is not set to true");
411
+ recommendations.push(`Set destructiveHint=true for ${tool.name} - this tool appears to perform destructive operations`);
412
+ }
413
+ return {
414
+ toolName: tool.name,
415
+ hasAnnotations,
416
+ annotations: hasAnnotations ? annotations : undefined,
417
+ inferredBehavior,
418
+ issues,
419
+ recommendations,
420
+ };
421
+ }
422
+ /**
423
+ * Extract annotations from a tool
424
+ * MCP SDK may have annotations in different locations
425
+ */
426
+ extractAnnotations(tool) {
427
+ // Try to find annotations in various locations
428
+ const toolAny = tool;
429
+ // Check direct properties
430
+ let readOnlyHint = toolAny.readOnlyHint;
431
+ let destructiveHint = toolAny.destructiveHint;
432
+ let idempotentHint = toolAny.idempotentHint;
433
+ let openWorldHint = toolAny.openWorldHint;
434
+ // Check annotations object (MCP 2024-11 spec)
435
+ if (toolAny.annotations) {
436
+ readOnlyHint = readOnlyHint ?? toolAny.annotations.readOnlyHint;
437
+ destructiveHint = destructiveHint ?? toolAny.annotations.destructiveHint;
438
+ idempotentHint = idempotentHint ?? toolAny.annotations.idempotentHint;
439
+ openWorldHint = openWorldHint ?? toolAny.annotations.openWorldHint;
440
+ }
441
+ // Check metadata (some servers use this)
442
+ if (toolAny.metadata) {
443
+ readOnlyHint = readOnlyHint ?? toolAny.metadata.readOnlyHint;
444
+ destructiveHint = destructiveHint ?? toolAny.metadata.destructiveHint;
445
+ }
446
+ return {
447
+ readOnlyHint,
448
+ destructiveHint,
449
+ title: toolAny.title || toolAny.annotations?.title,
450
+ description: tool.description,
451
+ idempotentHint,
452
+ openWorldHint,
453
+ };
454
+ }
455
+ /**
456
+ * Infer expected behavior from tool name and description
457
+ */
458
+ inferBehavior(toolName, description) {
459
+ const lowerName = toolName.toLowerCase();
460
+ const lowerDesc = (description || "").toLowerCase();
461
+ // Check for destructive patterns first (higher priority)
462
+ for (const pattern of DESTRUCTIVE_PATTERNS) {
463
+ if (pattern.test(lowerName)) {
464
+ return {
465
+ expectedReadOnly: false,
466
+ expectedDestructive: true,
467
+ reason: `Tool name matches destructive pattern: ${pattern.source}`,
468
+ };
469
+ }
470
+ }
471
+ // Check for read-only patterns
472
+ for (const pattern of READ_ONLY_PATTERNS) {
473
+ if (pattern.test(lowerName)) {
474
+ return {
475
+ expectedReadOnly: true,
476
+ expectedDestructive: false,
477
+ reason: `Tool name matches read-only pattern: ${pattern.source}`,
478
+ };
479
+ }
480
+ }
481
+ // Check for write patterns (not destructive but not read-only)
482
+ for (const pattern of WRITE_PATTERNS) {
483
+ if (pattern.test(lowerName)) {
484
+ return {
485
+ expectedReadOnly: false,
486
+ expectedDestructive: false,
487
+ reason: `Tool name matches write pattern: ${pattern.source}`,
488
+ };
489
+ }
490
+ }
491
+ // Check description for hints
492
+ if (lowerDesc.includes("delete") || lowerDesc.includes("remove")) {
493
+ return {
494
+ expectedReadOnly: false,
495
+ expectedDestructive: true,
496
+ reason: "Description mentions delete/remove operations",
497
+ };
498
+ }
499
+ if (lowerDesc.includes("read") ||
500
+ lowerDesc.includes("get") ||
501
+ lowerDesc.includes("fetch")) {
502
+ return {
503
+ expectedReadOnly: true,
504
+ expectedDestructive: false,
505
+ reason: "Description suggests read-only operation",
506
+ };
507
+ }
508
+ // Default: assume write (safer to warn about missing annotations)
509
+ return {
510
+ expectedReadOnly: false,
511
+ expectedDestructive: false,
512
+ reason: "Could not infer from name pattern - defaulting to write operation",
513
+ };
514
+ }
515
+ /**
516
+ * Determine overall status
517
+ */
518
+ determineAnnotationStatus(results, totalTools) {
519
+ if (totalTools === 0)
520
+ return "PASS";
521
+ const annotatedCount = results.filter((r) => r.hasAnnotations).length;
522
+ const misalignedCount = results.filter((r) => r.issues.some((i) => i.includes("misaligned"))).length;
523
+ const destructiveWithoutHint = results.filter((r) => r.issues.some((i) => i.includes("destructive") && i.includes("not set"))).length;
524
+ // Destructive tools without proper hints = FAIL (check this FIRST)
525
+ if (destructiveWithoutHint > 0) {
526
+ return "FAIL";
527
+ }
528
+ // All tools annotated and no misalignments = PASS
529
+ if (annotatedCount === totalTools && misalignedCount === 0) {
530
+ return "PASS";
531
+ }
532
+ // Some annotations missing = NEED_MORE_INFO
533
+ const annotationRate = annotatedCount / totalTools;
534
+ if (annotationRate >= 0.8) {
535
+ return "NEED_MORE_INFO";
536
+ }
537
+ // Mostly missing annotations = FAIL
538
+ if (annotationRate < 0.5) {
539
+ return "FAIL";
540
+ }
541
+ return "NEED_MORE_INFO";
542
+ }
543
+ /**
544
+ * Generate explanation
545
+ */
546
+ generateExplanation(annotatedCount, missingCount, misalignedCount, totalTools) {
547
+ const parts = [];
548
+ if (totalTools === 0) {
549
+ return "No tools found to assess for annotations.";
550
+ }
551
+ parts.push(`Tool annotation coverage: ${annotatedCount}/${totalTools} tools have annotations.`);
552
+ if (missingCount > 0) {
553
+ parts.push(`${missingCount} tool(s) are missing required annotations (readOnlyHint, destructiveHint).`);
554
+ }
555
+ if (misalignedCount > 0) {
556
+ parts.push(`${misalignedCount} tool(s) have potentially misaligned annotations based on naming patterns.`);
557
+ }
558
+ if (missingCount === 0 && misalignedCount === 0) {
559
+ parts.push("All tools are properly annotated.");
560
+ }
561
+ return parts.join(" ");
562
+ }
563
+ /**
564
+ * Generate recommendations
565
+ */
566
+ generateRecommendations(results) {
567
+ const recommendations = [];
568
+ // Collect unique recommendations from all tools
569
+ const allRecs = new Set();
570
+ for (const result of results) {
571
+ for (const rec of result.recommendations) {
572
+ allRecs.add(rec);
573
+ }
574
+ }
575
+ // Prioritize destructive tool warnings
576
+ const destructiveRecs = Array.from(allRecs).filter((r) => r.includes("destructive"));
577
+ const otherRecs = Array.from(allRecs).filter((r) => !r.includes("destructive"));
578
+ if (destructiveRecs.length > 0) {
579
+ recommendations.push("PRIORITY: The following tools appear to perform destructive operations but lack proper destructiveHint annotation:");
580
+ recommendations.push(...destructiveRecs.slice(0, 5));
581
+ }
582
+ if (otherRecs.length > 0) {
583
+ recommendations.push(...otherRecs.slice(0, 5));
584
+ }
585
+ if (recommendations.length === 0) {
586
+ recommendations.push("All tools have proper annotations. No action required.");
587
+ }
588
+ else {
589
+ recommendations.push("Reference: MCP Directory Policy #17 requires tools to have readOnlyHint and destructiveHint annotations.");
590
+ }
591
+ return recommendations;
592
+ }
593
+ }