@bryan-thompson/inspector-assessment-server 1.32.2 → 1.32.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.
@@ -103,6 +103,31 @@ describe("POST /assessment/save", () => {
103
103
  expect(response.status).toBe(200);
104
104
  expect(response.body.path).toContain("unknown");
105
105
  });
106
+ it("should return 400 when assessment is not an object", async () => {
107
+ const response = await request(app)
108
+ .post("/assessment/save")
109
+ .set("x-mcp-proxy-auth", `Bearer ${sessionToken}`)
110
+ .send({ serverName: "test", assessment: "not-an-object" });
111
+ expect(response.status).toBe(400);
112
+ expect(response.body.success).toBe(false);
113
+ });
114
+ it("should return 400 when assessment is an array", async () => {
115
+ const response = await request(app)
116
+ .post("/assessment/save")
117
+ .set("x-mcp-proxy-auth", `Bearer ${sessionToken}`)
118
+ .send({ serverName: "test", assessment: [1, 2, 3] });
119
+ expect(response.status).toBe(400);
120
+ expect(response.body.success).toBe(false);
121
+ });
122
+ it("should return 400 when serverName exceeds max length", async () => {
123
+ const longName = "a".repeat(300);
124
+ const response = await request(app)
125
+ .post("/assessment/save")
126
+ .set("x-mcp-proxy-auth", `Bearer ${sessionToken}`)
127
+ .send({ serverName: longName, assessment: {} });
128
+ expect(response.status).toBe(400);
129
+ expect(response.body.success).toBe(false);
130
+ });
106
131
  it("should require authentication", async () => {
107
132
  const response = await request(app)
108
133
  .post("/assessment/save")
package/build/index.js CHANGED
@@ -18,7 +18,13 @@ import { findActualExecutable } from "spawn-rx";
18
18
  import mcpProxy from "./mcpProxy.js";
19
19
  import { is401Error, getHttpHeaders, updateHeadersInPlace } from "./helpers.js";
20
20
  import { randomUUID, randomBytes, timingSafeEqual } from "node:crypto";
21
+ import { z } from "zod";
21
22
  const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277";
23
+ // Schema for /assessment/save endpoint validation (Issue #87)
24
+ const AssessmentSaveSchema = z.object({
25
+ serverName: z.string().min(1).max(255).optional().default("unknown"),
26
+ assessment: z.object({}).passthrough(), // Must be object, allow any properties
27
+ });
22
28
  const defaultEnvironment = {
23
29
  ...getDefaultEnvironment(),
24
30
  ...(process.env.MCP_ENV_VARS ? JSON.parse(process.env.MCP_ENV_VARS) : {}),
@@ -542,15 +548,32 @@ app.get("/health", (req, res) => {
542
548
  app.post("/assessment/save", originValidationMiddleware, authMiddleware, express.json({ limit: "10mb" }), // Allow large JSON payloads
543
549
  async (req, res) => {
544
550
  try {
545
- const { serverName, assessment } = req.body;
546
- const sanitizedName = (serverName || "unknown").replace(/[^a-zA-Z0-9-_]/g, "_");
551
+ // Validate request body (Issue #87)
552
+ const parseResult = AssessmentSaveSchema.safeParse(req.body);
553
+ if (!parseResult.success) {
554
+ return res.status(400).json({
555
+ success: false,
556
+ error: "Invalid request structure",
557
+ details: parseResult.error.format(),
558
+ });
559
+ }
560
+ const { serverName, assessment } = parseResult.data;
561
+ // Check assessment size (10MB limit)
562
+ const jsonStr = JSON.stringify(assessment, null, 2);
563
+ if (jsonStr.length > 10 * 1024 * 1024) {
564
+ return res.status(413).json({
565
+ success: false,
566
+ error: "Assessment too large (max 10MB)",
567
+ });
568
+ }
569
+ const sanitizedName = serverName.replace(/[^a-zA-Z0-9-_]/g, "_");
547
570
  const filename = `/tmp/inspector-assessment-${sanitizedName}.json`;
548
571
  // Delete old file if exists (cleanup)
549
572
  if (fs.existsSync(filename)) {
550
573
  fs.unlinkSync(filename);
551
574
  }
552
575
  // Save new assessment
553
- fs.writeFileSync(filename, JSON.stringify(assessment, null, 2));
576
+ fs.writeFileSync(filename, jsonStr);
554
577
  res.json({
555
578
  success: true,
556
579
  path: filename,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bryan-thompson/inspector-assessment-server",
3
- "version": "1.32.2",
3
+ "version": "1.32.4",
4
4
  "description": "Server-side application for the Enhanced MCP Inspector with assessment capabilities",
5
5
  "license": "MIT",
6
6
  "author": "Bryan Thompson <bryan@triepod.ai>",