@bryan-thompson/inspector-assessment 1.7.1 → 1.8.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.
- package/README.md +6 -1
- package/client/dist/assets/{OAuthCallback-cGhwkoyY.js → OAuthCallback-C6NJ8fGr.js} +1 -1
- package/client/dist/assets/{OAuthDebugCallback-2rmUqser.js → OAuthDebugCallback-MIqvflwd.js} +1 -1
- package/client/dist/assets/{index-BnFixpvH.js → index-CW7GS_di.js} +759 -283
- package/client/dist/assets/{index-Bj7kEsw0.css → index-Cuc9GxjD.css} +5 -1
- package/client/dist/index.html +2 -2
- package/client/lib/services/assessment/lib/concurrencyLimit.d.ts +20 -0
- package/client/lib/services/assessment/lib/concurrencyLimit.d.ts.map +1 -0
- package/client/lib/services/assessment/lib/concurrencyLimit.js +51 -0
- package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/ErrorHandlingAssessor.js +14 -4
- package/client/lib/services/assessment/modules/FunctionalityAssessor.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/FunctionalityAssessor.js +15 -5
- package/client/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/SecurityAssessor.js +15 -5
- package/package.json +6 -6
- package/server/build/index.js +20 -5
- package/client/README.md +0 -50
|
@@ -56,6 +56,8 @@ pre[class*="language-"] {
|
|
|
56
56
|
-moz-tab-size: 4;
|
|
57
57
|
-o-tab-size: 4;
|
|
58
58
|
tab-size: 4;
|
|
59
|
+
|
|
60
|
+
-webkit-hyphens: none;
|
|
59
61
|
hyphens: none;
|
|
60
62
|
}
|
|
61
63
|
|
|
@@ -281,7 +283,7 @@ pre[class*="language-"] {
|
|
|
281
283
|
--tw-contain-paint: ;
|
|
282
284
|
--tw-contain-style: ;
|
|
283
285
|
}/*
|
|
284
|
-
! tailwindcss v3.4.
|
|
286
|
+
! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com
|
|
285
287
|
*//*
|
|
286
288
|
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
|
|
287
289
|
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
|
|
@@ -2099,7 +2101,9 @@ video {
|
|
|
2099
2101
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
|
2100
2102
|
}
|
|
2101
2103
|
.transition {
|
|
2104
|
+
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
|
|
2102
2105
|
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
|
|
2106
|
+
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
|
|
2103
2107
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
2104
2108
|
transition-duration: 150ms;
|
|
2105
2109
|
}
|
package/client/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-CW7GS_di.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Cuc9GxjD.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root" class="w-full"></div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple concurrency limiter for parallel async operations
|
|
3
|
+
* Provides the same interface as p-limit but is CJS-compatible
|
|
4
|
+
*/
|
|
5
|
+
export type LimitFunction = <T>(fn: () => Promise<T>) => Promise<T>;
|
|
6
|
+
/**
|
|
7
|
+
* Creates a concurrency limiter that allows only a specified number
|
|
8
|
+
* of async operations to run simultaneously
|
|
9
|
+
*
|
|
10
|
+
* @param concurrency - Maximum number of concurrent operations
|
|
11
|
+
* @returns A function that wraps async operations with the concurrency limit
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const limit = createConcurrencyLimit(5);
|
|
15
|
+
* const results = await Promise.all(
|
|
16
|
+
* items.map(item => limit(() => processItem(item)))
|
|
17
|
+
* );
|
|
18
|
+
*/
|
|
19
|
+
export declare function createConcurrencyLimit(concurrency: number): LimitFunction;
|
|
20
|
+
//# sourceMappingURL=concurrencyLimit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrencyLimit.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/lib/concurrencyLimit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAEpE;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,CAyCzE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple concurrency limiter for parallel async operations
|
|
3
|
+
* Provides the same interface as p-limit but is CJS-compatible
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Creates a concurrency limiter that allows only a specified number
|
|
7
|
+
* of async operations to run simultaneously
|
|
8
|
+
*
|
|
9
|
+
* @param concurrency - Maximum number of concurrent operations
|
|
10
|
+
* @returns A function that wraps async operations with the concurrency limit
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const limit = createConcurrencyLimit(5);
|
|
14
|
+
* const results = await Promise.all(
|
|
15
|
+
* items.map(item => limit(() => processItem(item)))
|
|
16
|
+
* );
|
|
17
|
+
*/
|
|
18
|
+
export function createConcurrencyLimit(concurrency) {
|
|
19
|
+
if (concurrency < 1) {
|
|
20
|
+
throw new Error("Concurrency must be at least 1");
|
|
21
|
+
}
|
|
22
|
+
let activeCount = 0;
|
|
23
|
+
const queue = [];
|
|
24
|
+
const next = () => {
|
|
25
|
+
if (activeCount < concurrency && queue.length > 0) {
|
|
26
|
+
const { fn, resolve, reject } = queue.shift();
|
|
27
|
+
activeCount++;
|
|
28
|
+
fn()
|
|
29
|
+
.then((result) => {
|
|
30
|
+
activeCount--;
|
|
31
|
+
resolve(result);
|
|
32
|
+
next();
|
|
33
|
+
})
|
|
34
|
+
.catch((error) => {
|
|
35
|
+
activeCount--;
|
|
36
|
+
reject(error);
|
|
37
|
+
next();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
return (fn) => {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
queue.push({
|
|
44
|
+
fn: fn,
|
|
45
|
+
resolve: resolve,
|
|
46
|
+
reject,
|
|
47
|
+
});
|
|
48
|
+
next();
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorHandlingAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ErrorHandlingAssessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,uBAAuB,EAIxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"ErrorHandlingAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ErrorHandlingAssessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,uBAAuB,EAIxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,qBAAa,qBAAsB,SAAQ,YAAY;IAC/C,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA8D1E,OAAO,CAAC,qBAAqB;YA8Cf,qBAAqB;YAuBrB,qBAAqB;YAmGrB,cAAc;YAmFd,iBAAiB;YA8DjB,kBAAkB;IA6DhC,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,uBAAuB;IAgC/B,OAAO,CAAC,0BAA0B;IAgClC,OAAO,CAAC,uBAAuB;IA4B/B,OAAO,CAAC,gBAAgB;IAoGxB,OAAO,CAAC,4BAA4B;IAapC,OAAO,CAAC,mBAAmB;IAuE3B,OAAO,CAAC,uBAAuB;CA4ChC"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Tests error handling and input validation
|
|
4
4
|
*/
|
|
5
5
|
import { BaseAssessor } from "./BaseAssessor.js";
|
|
6
|
+
import { createConcurrencyLimit } from "../lib/concurrencyLimit.js";
|
|
6
7
|
export class ErrorHandlingAssessor extends BaseAssessor {
|
|
7
8
|
async assess(context) {
|
|
8
9
|
this.log("Starting error handling assessment");
|
|
@@ -10,14 +11,23 @@ export class ErrorHandlingAssessor extends BaseAssessor {
|
|
|
10
11
|
let passedTests = 0;
|
|
11
12
|
// Test a sample of tools for error handling
|
|
12
13
|
const toolsToTest = this.selectToolsForTesting(context.tools);
|
|
13
|
-
|
|
14
|
+
// Parallel tool testing with concurrency limit
|
|
15
|
+
const concurrency = this.config.maxParallelTests ?? 5;
|
|
16
|
+
const limit = createConcurrencyLimit(concurrency);
|
|
17
|
+
this.log(`Testing ${toolsToTest.length} tools for error handling with concurrency limit of ${concurrency}`);
|
|
18
|
+
const allToolTests = await Promise.all(toolsToTest.map((tool) => limit(async () => {
|
|
14
19
|
const toolTests = await this.testToolErrorHandling(tool, context.callTool);
|
|
15
|
-
testDetails.push(...toolTests);
|
|
16
|
-
passedTests += toolTests.filter((t) => t.passed).length;
|
|
17
20
|
// Add delay between tests to avoid rate limiting
|
|
18
|
-
if (this.config.delayBetweenTests &&
|
|
21
|
+
if (this.config.delayBetweenTests &&
|
|
22
|
+
this.config.delayBetweenTests > 0) {
|
|
19
23
|
await this.sleep(this.config.delayBetweenTests);
|
|
20
24
|
}
|
|
25
|
+
return toolTests;
|
|
26
|
+
})));
|
|
27
|
+
// Post-process results after parallel execution
|
|
28
|
+
for (const toolTests of allToolTests) {
|
|
29
|
+
testDetails.push(...toolTests);
|
|
30
|
+
passedTests += toolTests.filter((t) => t.passed).length;
|
|
21
31
|
}
|
|
22
32
|
this.testCount = testDetails.length;
|
|
23
33
|
const metrics = this.calculateMetrics(testDetails, passedTests);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FunctionalityAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/FunctionalityAssessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,uBAAuB,EAAkB,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"FunctionalityAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/FunctionalityAssessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,uBAAuB,EAAkB,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAI9D,qBAAa,qBAAsB,SAAQ,YAAY;IACrD;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoCvB,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,uBAAuB,CAAC;YAiF5D,QAAQ;IA6EtB,OAAO,CAAC,qBAAqB;IA2B7B,OAAO,CAAC,kBAAkB;IA0FnB,iBAAiB,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO;IAI9C,OAAO,CAAC,mBAAmB;CA+B5B"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { BaseAssessor } from "./BaseAssessor.js";
|
|
6
6
|
import { ResponseValidator } from "../ResponseValidator.js";
|
|
7
|
+
import { createConcurrencyLimit } from "../lib/concurrencyLimit.js";
|
|
7
8
|
export class FunctionalityAssessor extends BaseAssessor {
|
|
8
9
|
/**
|
|
9
10
|
* Select tools for testing based on configuration
|
|
@@ -38,21 +39,30 @@ export class FunctionalityAssessor extends BaseAssessor {
|
|
|
38
39
|
let workingTools = 0;
|
|
39
40
|
// Select tools for testing
|
|
40
41
|
const toolsToTest = this.selectToolsForTesting(context.tools);
|
|
41
|
-
|
|
42
|
+
// Parallel tool testing with concurrency limit
|
|
43
|
+
const concurrency = this.config.maxParallelTests ?? 5;
|
|
44
|
+
const limit = createConcurrencyLimit(concurrency);
|
|
45
|
+
this.log(`Testing ${toolsToTest.length} tools with concurrency limit of ${concurrency}`);
|
|
46
|
+
const results = await Promise.all(toolsToTest.map((tool) => limit(async () => {
|
|
42
47
|
this.testCount++;
|
|
43
48
|
const result = await this.testTool(tool, context.callTool);
|
|
44
|
-
toolResults.push(result);
|
|
45
49
|
// Add delay between tests to avoid rate limiting
|
|
46
|
-
if (this.config.delayBetweenTests &&
|
|
50
|
+
if (this.config.delayBetweenTests &&
|
|
51
|
+
this.config.delayBetweenTests > 0) {
|
|
47
52
|
await this.sleep(this.config.delayBetweenTests);
|
|
48
53
|
}
|
|
54
|
+
return result;
|
|
55
|
+
})));
|
|
56
|
+
// Post-process results after parallel execution
|
|
57
|
+
for (const result of results) {
|
|
58
|
+
toolResults.push(result);
|
|
49
59
|
if (result.status === "working") {
|
|
50
60
|
workingTools++;
|
|
51
61
|
}
|
|
52
62
|
else if (result.status === "broken") {
|
|
53
|
-
brokenTools.push(
|
|
63
|
+
brokenTools.push(result.toolName);
|
|
54
64
|
if (this.config.skipBrokenTools) {
|
|
55
|
-
this.log(`Skipping further tests for broken tool: ${
|
|
65
|
+
this.log(`Skipping further tests for broken tool: ${result.toolName}`);
|
|
56
66
|
}
|
|
57
67
|
}
|
|
58
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SecurityAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/SecurityAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,kBAAkB,EAInB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"SecurityAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/SecurityAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,kBAAkB,EAInB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAU9D,qBAAa,gBAAiB,SAAQ,YAAY;IAC1C,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAuFrE;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAkC7B;;;;OAIG;YACW,yBAAyB;IAgHvC;;;;OAIG;YACW,qBAAqB;IAwGnC;;OAEG;YACW,WAAW;IA2HzB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAkDzB;;;OAGG;IACH,OAAO,CAAC,8BAA8B;IAmDtC;;OAEG;IACH,OAAO,CAAC,aAAa;IA+BrB;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAgClC;;;OAGG;IACH,OAAO,CAAC,eAAe;IA6HvB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAiE7B;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IAqC5B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAsB3B;;;;;;;OAOG;IACH,OAAO,CAAC,oBAAoB;IAkC5B;;OAEG;YACW,+BAA+B;IAiC7C;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAYjC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA0B/B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAkEnC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAuI3B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAsB5B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,oBAAoB;IAiM5B;;;;;;OAMG;IACH,OAAO,CAAC,wBAAwB;IAiDhC;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IA8BhC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAW9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,oBAAoB;IAoE5B;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;;OAGG;IACH,OAAO,CAAC,eAAe;IASvB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAiB9B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;CAmB3B"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { BaseAssessor } from "./BaseAssessor.js";
|
|
9
9
|
import { getAllAttackPatterns, getPayloadsForAttack, } from "../../../lib/securityPatterns.js";
|
|
10
10
|
import { ToolClassifier, ToolCategory } from "../ToolClassifier.js";
|
|
11
|
+
import { createConcurrencyLimit } from "../lib/concurrencyLimit.js";
|
|
11
12
|
export class SecurityAssessor extends BaseAssessor {
|
|
12
13
|
async assess(context) {
|
|
13
14
|
// Select tools for testing first
|
|
@@ -108,8 +109,12 @@ export class SecurityAssessor extends BaseAssessor {
|
|
|
108
109
|
const attackPatterns = getAllAttackPatterns();
|
|
109
110
|
// Select tools for testing
|
|
110
111
|
const toolsToTest = this.selectToolsForTesting(context.tools);
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
// Parallel tool testing with concurrency limit
|
|
113
|
+
const concurrency = this.config.maxParallelTests ?? 5;
|
|
114
|
+
const limit = createConcurrencyLimit(concurrency);
|
|
115
|
+
this.log(`Starting ADVANCED security assessment - testing ${toolsToTest.length} tools with ${attackPatterns.length} security patterns (~${toolsToTest.length * attackPatterns.length * 3} tests) [concurrency: ${concurrency}]`);
|
|
116
|
+
const allToolResults = await Promise.all(toolsToTest.map((tool) => limit(async () => {
|
|
117
|
+
const toolResults = [];
|
|
113
118
|
// Tools with no input parameters can't be exploited via payload injection
|
|
114
119
|
// Add passing results so they appear in the UI
|
|
115
120
|
if (!this.hasInputParameters(tool)) {
|
|
@@ -119,7 +124,7 @@ export class SecurityAssessor extends BaseAssessor {
|
|
|
119
124
|
const payloads = getPayloadsForAttack(attackPattern.attackName);
|
|
120
125
|
// Add one passing result per payload type
|
|
121
126
|
for (const payload of payloads) {
|
|
122
|
-
|
|
127
|
+
toolResults.push({
|
|
123
128
|
testName: attackPattern.attackName,
|
|
124
129
|
description: payload.description,
|
|
125
130
|
payload: payload.payload,
|
|
@@ -130,7 +135,7 @@ export class SecurityAssessor extends BaseAssessor {
|
|
|
130
135
|
});
|
|
131
136
|
}
|
|
132
137
|
}
|
|
133
|
-
|
|
138
|
+
return toolResults;
|
|
134
139
|
}
|
|
135
140
|
this.log(`Testing ${tool.name} with all attack patterns`);
|
|
136
141
|
// Test with each attack type (all patterns in advanced mode)
|
|
@@ -142,7 +147,7 @@ export class SecurityAssessor extends BaseAssessor {
|
|
|
142
147
|
this.testCount++;
|
|
143
148
|
try {
|
|
144
149
|
const result = await this.testPayload(tool, attackPattern.attackName, payload, context.callTool);
|
|
145
|
-
|
|
150
|
+
toolResults.push(result);
|
|
146
151
|
if (result.vulnerable) {
|
|
147
152
|
this.log(`🚨 VULNERABILITY: ${tool.name} - ${attackPattern.attackName} (${payload.payloadType}: ${payload.description})`);
|
|
148
153
|
}
|
|
@@ -156,6 +161,11 @@ export class SecurityAssessor extends BaseAssessor {
|
|
|
156
161
|
}
|
|
157
162
|
}
|
|
158
163
|
}
|
|
164
|
+
return toolResults;
|
|
165
|
+
})));
|
|
166
|
+
// Flatten all tool results into the main results array
|
|
167
|
+
for (const toolResults of allToolResults) {
|
|
168
|
+
results.push(...toolResults);
|
|
159
169
|
}
|
|
160
170
|
this.log(`ADVANCED security assessment complete: ${results.length} tests executed, ${results.filter((r) => r.vulnerable).length} vulnerabilities found`);
|
|
161
171
|
return results;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bryan-thompson/inspector-assessment",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Enhanced MCP Inspector with comprehensive assessment capabilities for server validation",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bryan Thompson <bryan@triepod.ai>",
|
|
@@ -74,14 +74,14 @@
|
|
|
74
74
|
"access": "public"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@bryan-thompson/inspector-assessment-cli": "^1.
|
|
78
|
-
"@bryan-thompson/inspector-assessment-client": "^1.
|
|
79
|
-
"@bryan-thompson/inspector-assessment-server": "^1.
|
|
80
|
-
"@
|
|
81
|
-
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
77
|
+
"@bryan-thompson/inspector-assessment-cli": "^1.7.1",
|
|
78
|
+
"@bryan-thompson/inspector-assessment-client": "^1.7.1",
|
|
79
|
+
"@bryan-thompson/inspector-assessment-server": "^1.7.1",
|
|
80
|
+
"@modelcontextprotocol/sdk": "^1.24.3",
|
|
82
81
|
"concurrently": "^9.2.0",
|
|
83
82
|
"node-fetch": "^3.3.2",
|
|
84
83
|
"open": "^10.2.0",
|
|
84
|
+
"p-limit": "^7.2.0",
|
|
85
85
|
"shell-quote": "^1.8.3",
|
|
86
86
|
"spawn-rx": "^5.1.2",
|
|
87
87
|
"ts-node": "^10.9.2",
|
package/server/build/index.js
CHANGED
|
@@ -9,7 +9,7 @@ const fetch = nodeFetch;
|
|
|
9
9
|
const Headers = NodeHeaders;
|
|
10
10
|
import { SSEClientTransport, SseError, } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
11
11
|
import { StdioClientTransport, getDefaultEnvironment, } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
12
|
-
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
12
|
+
import { StreamableHTTPClientTransport, StreamableHTTPError, } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
13
13
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
14
14
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
15
15
|
import express from "express";
|
|
@@ -31,6 +31,21 @@ const { values } = parseArgs({
|
|
|
31
31
|
"server-url": { type: "string", default: "" },
|
|
32
32
|
},
|
|
33
33
|
});
|
|
34
|
+
/**
|
|
35
|
+
* Helper function to detect 401 Unauthorized errors from various transport types.
|
|
36
|
+
* StreamableHTTPClientTransport throws a generic Error with "HTTP 401" in the message
|
|
37
|
+
* when there's no authProvider configured, while SSEClientTransport throws SseError.
|
|
38
|
+
*/
|
|
39
|
+
const is401Error = (error) => {
|
|
40
|
+
if (error instanceof SseError && error.code === 401)
|
|
41
|
+
return true;
|
|
42
|
+
if (error instanceof StreamableHTTPError && error.code === 401)
|
|
43
|
+
return true;
|
|
44
|
+
if (error instanceof Error &&
|
|
45
|
+
(error.message.includes("HTTP 401") || error.message.includes("(401)")))
|
|
46
|
+
return true;
|
|
47
|
+
return false;
|
|
48
|
+
};
|
|
34
49
|
// Function to get HTTP headers.
|
|
35
50
|
const getHttpHeaders = (req) => {
|
|
36
51
|
const headers = {};
|
|
@@ -389,8 +404,8 @@ app.post("/mcp", originValidationMiddleware, authMiddleware, async (req, res) =>
|
|
|
389
404
|
await webAppTransport.handleRequest(req, res, req.body);
|
|
390
405
|
}
|
|
391
406
|
catch (error) {
|
|
392
|
-
if (error
|
|
393
|
-
console.error("Received 401 Unauthorized from MCP server:", error.message);
|
|
407
|
+
if (is401Error(error)) {
|
|
408
|
+
console.error("Received 401 Unauthorized from MCP server:", error instanceof Error ? error.message : error);
|
|
394
409
|
res.status(401).json(error);
|
|
395
410
|
return;
|
|
396
411
|
}
|
|
@@ -522,7 +537,7 @@ app.get("/stdio", originValidationMiddleware, authMiddleware, async (req, res) =
|
|
|
522
537
|
});
|
|
523
538
|
}
|
|
524
539
|
catch (error) {
|
|
525
|
-
if (error
|
|
540
|
+
if (is401Error(error)) {
|
|
526
541
|
console.error("Received 401 Unauthorized from MCP server. Authentication failure.");
|
|
527
542
|
res.status(401).json(error);
|
|
528
543
|
return;
|
|
@@ -553,7 +568,7 @@ app.get("/sse", originValidationMiddleware, authMiddleware, async (req, res) =>
|
|
|
553
568
|
});
|
|
554
569
|
}
|
|
555
570
|
catch (error) {
|
|
556
|
-
if (error
|
|
571
|
+
if (is401Error(error)) {
|
|
557
572
|
console.error("Received 401 Unauthorized from MCP server. Authentication failure.");
|
|
558
573
|
res.status(401).json(error);
|
|
559
574
|
return;
|
package/client/README.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# React + TypeScript + Vite
|
|
2
|
-
|
|
3
|
-
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
|
4
|
-
|
|
5
|
-
Currently, two official plugins are available:
|
|
6
|
-
|
|
7
|
-
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
|
8
|
-
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
9
|
-
|
|
10
|
-
## Expanding the ESLint configuration
|
|
11
|
-
|
|
12
|
-
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
|
13
|
-
|
|
14
|
-
- Configure the top-level `parserOptions` property like this:
|
|
15
|
-
|
|
16
|
-
```js
|
|
17
|
-
export default tseslint.config({
|
|
18
|
-
languageOptions: {
|
|
19
|
-
// other options...
|
|
20
|
-
parserOptions: {
|
|
21
|
-
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
|
|
22
|
-
tsconfigRootDir: import.meta.dirname,
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
|
|
29
|
-
- Optionally add `...tseslint.configs.stylisticTypeChecked`
|
|
30
|
-
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
|
|
31
|
-
|
|
32
|
-
```js
|
|
33
|
-
// eslint.config.js
|
|
34
|
-
import react from "eslint-plugin-react";
|
|
35
|
-
|
|
36
|
-
export default tseslint.config({
|
|
37
|
-
// Set the react version
|
|
38
|
-
settings: { react: { version: "18.3" } },
|
|
39
|
-
plugins: {
|
|
40
|
-
// Add the react plugin
|
|
41
|
-
react,
|
|
42
|
-
},
|
|
43
|
-
rules: {
|
|
44
|
-
// other rules...
|
|
45
|
-
// Enable its recommended rules
|
|
46
|
-
...react.configs.recommended.rules,
|
|
47
|
-
...react.configs["jsx-runtime"].rules,
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
```
|