@pagopa/dx-mcpserver 0.2.2 → 0.2.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.
@@ -5,10 +5,7 @@ import { resolveToWebsiteUrl } from "../services/bedrock.js";
5
5
  import { parseJsonBody, sendErrorResponse, sendJsonResponse, } from "../utils/http.js";
6
6
  const AskBodySchema = z.object({
7
7
  query: z
8
- .string({
9
- invalid_type_error: "Missing required field: query",
10
- required_error: "Missing required field: query",
11
- })
8
+ .string({ error: "Missing required field: query" })
12
9
  .trim()
13
10
  .min(1, "Missing required field: query"),
14
11
  });
@@ -25,7 +22,11 @@ export async function handleAskEndpoint(req, res, config, kbRuntimeClient) {
25
22
  }
26
23
  const result = AskBodySchema.safeParse(jsonBody);
27
24
  if (!result.success) {
28
- return sendErrorResponse(res, 400, result.error.errors[0].message);
25
+ const firstIssue = result.error.issues[0];
26
+ if (!firstIssue) {
27
+ throw new Error("Request validation failed without any issues");
28
+ }
29
+ return sendErrorResponse(res, 400, firstIssue.message);
29
30
  }
30
31
  const { query } = result.data;
31
32
  const response = await retrieveAndGenerate(config.aws.knowledgeBaseId, config.aws.modelArn, query, kbRuntimeClient);
@@ -4,19 +4,14 @@ import { queryKnowledgeBaseStructured } from "../services/bedrock.js";
4
4
  import { parseJsonBody, sendErrorResponse, sendJsonResponse, } from "../utils/http.js";
5
5
  const SearchBodySchema = z.object({
6
6
  number_of_results: z
7
- .number({
8
- invalid_type_error: "number_of_results must be between 1 and 20",
9
- })
7
+ .number({ error: "number_of_results must be between 1 and 20" })
10
8
  .int()
11
9
  .min(1, "number_of_results must be between 1 and 20")
12
10
  .max(20, "number_of_results must be between 1 and 20")
13
11
  .optional()
14
12
  .default(5),
15
13
  query: z
16
- .string({
17
- invalid_type_error: "Missing required field: query",
18
- required_error: "Missing required field: query",
19
- })
14
+ .string({ error: "Missing required field: query" })
20
15
  .trim()
21
16
  .min(1, "Missing required field: query"),
22
17
  });
@@ -33,7 +28,11 @@ export async function handleSearchEndpoint(req, res, config, kbRuntimeClient) {
33
28
  }
34
29
  const result = SearchBodySchema.safeParse(jsonBody);
35
30
  if (!result.success) {
36
- return sendErrorResponse(res, 400, result.error.errors[0].message);
31
+ const firstIssue = result.error.issues[0];
32
+ if (!firstIssue) {
33
+ throw new Error("Request validation failed without any issues");
34
+ }
35
+ return sendErrorResponse(res, 400, firstIssue.message);
37
36
  }
38
37
  const { number_of_results: numberOfResults, query } = result.data;
39
38
  const results = await queryKnowledgeBaseStructured(config.aws.knowledgeBaseId, query, kbRuntimeClient, numberOfResults, config.aws.rerankingEnabled);
@@ -64,9 +64,8 @@ export function createServer({ enabledPrompts, requestId, toolDefinitions, }) {
64
64
  ? fieldSchema
65
65
  : fieldSchema.optional();
66
66
  }
67
- const zodObject = z.object(argsSchemaShape);
68
67
  mcpServer.registerPrompt(catalogEntry.prompt.name, {
69
- argsSchema: zodObject.shape,
68
+ argsSchema: argsSchemaShape,
70
69
  description: catalogEntry.prompt.description,
71
70
  }, async (args) => {
72
71
  const content = await decoratedPrompt.load(args || {});
@@ -22,14 +22,14 @@ describe("Query Validation", () => {
22
22
  shortQueries.forEach((input) => {
23
23
  const result = queryDocSchema.safeParse(input);
24
24
  expect(result.success).toBe(false);
25
- expect(result.error?.errors[0].message).toBe("Query must be at least 3 characters");
25
+ expect(result.error?.issues[0]?.message).toBe("Query must be at least 3 characters");
26
26
  });
27
27
  });
28
28
  it("should reject queries exceeding 500 characters", () => {
29
29
  const longQuery = { query: "a".repeat(501) };
30
30
  const result = queryDocSchema.safeParse(longQuery);
31
31
  expect(result.success).toBe(false);
32
- expect(result.error?.errors[0].message).toBe("Query must not exceed 500 characters");
32
+ expect(result.error?.issues[0]?.message).toBe("Query must not exceed 500 characters");
33
33
  });
34
34
  it("should reject missing query field", () => {
35
35
  const missingQuery = {};
@@ -1,6 +1,6 @@
1
1
  import { AxiosError, AxiosHeaders } from "axios";
2
2
  import { describe, expect, it } from "vitest";
3
- import { ZodError } from "zod";
3
+ import { z, ZodError } from "zod";
4
4
  import { handleApiError, isAxiosError, isZodError } from "../error-handling.js";
5
5
  /**
6
6
  * Helper to create an AxiosError with a response
@@ -73,49 +73,48 @@ describe("handleApiError - Axios network errors", () => {
73
73
  });
74
74
  describe("handleApiError - Zod validation errors", () => {
75
75
  it("should format single validation error", () => {
76
- const error = new ZodError([
77
- {
78
- code: "too_small",
79
- inclusive: true,
80
- message: "String must contain at least 3 character(s)",
81
- minimum: 3,
82
- path: ["query"],
83
- type: "string",
84
- },
85
- ]);
86
- expect(handleApiError(error)).toBe("Error: Invalid input - query: String must contain at least 3 character(s)");
76
+ const result = z
77
+ .object({
78
+ query: z.string().min(3, "String must contain at least 3 character(s)"),
79
+ })
80
+ .safeParse({ query: "" });
81
+ expect(result.success).toBe(false);
82
+ if (result.success) {
83
+ throw new Error("Expected validation to fail");
84
+ }
85
+ expect(handleApiError(result.error)).toBe("Error: Invalid input - query: String must contain at least 3 character(s)");
87
86
  });
88
87
  it("should format multiple validation errors", () => {
89
- const error = new ZodError([
90
- {
91
- code: "too_small",
92
- inclusive: true,
93
- message: "String must contain at least 3 character(s)",
94
- minimum: 3,
95
- path: ["query"],
96
- type: "string",
97
- },
98
- {
99
- code: "invalid_type",
100
- expected: "number",
101
- message: "Expected number, received string",
102
- path: ["page"],
103
- received: "string",
104
- },
105
- ]);
106
- expect(handleApiError(error)).toBe("Error: Invalid input - query: String must contain at least 3 character(s); page: Expected number, received string");
88
+ const result = z
89
+ .intersection(z.object({
90
+ query: z
91
+ .string()
92
+ .min(3, "String must contain at least 3 character(s)"),
93
+ }), z.object({
94
+ page: z.number({ error: "Expected number, received string" }),
95
+ }))
96
+ .safeParse({ page: "one", query: "" });
97
+ expect(result.success).toBe(false);
98
+ if (result.success) {
99
+ throw new Error("Expected validation to fail");
100
+ }
101
+ expect(handleApiError(result.error)).toBe("Error: Invalid input - query: String must contain at least 3 character(s); page: Expected number, received string");
107
102
  });
108
103
  it("should handle nested path errors", () => {
109
- const error = new ZodError([
110
- {
111
- code: "invalid_type",
112
- expected: "string",
113
- message: "Required",
114
- path: ["data", "nested", "field"],
115
- received: "undefined",
116
- },
117
- ]);
118
- expect(handleApiError(error)).toBe("Error: Invalid input - data.nested.field: Required");
104
+ const result = z
105
+ .object({
106
+ data: z.object({
107
+ nested: z.object({
108
+ field: z.string({ error: "Required" }),
109
+ }),
110
+ }),
111
+ })
112
+ .safeParse({ data: { nested: {} } });
113
+ expect(result.success).toBe(false);
114
+ if (result.success) {
115
+ throw new Error("Expected validation to fail");
116
+ }
117
+ expect(handleApiError(result.error)).toBe("Error: Invalid input - data.nested.field: Required");
119
118
  });
120
119
  });
121
120
  describe("handleApiError - generic errors", () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/dx-mcpserver",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "description": "An MCP server that supports developers using DX tools.",
6
6
  "repository": {
@@ -19,26 +19,26 @@
19
19
  "dx": "./dist/cli.js"
20
20
  },
21
21
  "dependencies": {
22
- "@aws-sdk/client-bedrock-agent-runtime": "^3.1030.0",
23
- "@aws-sdk/client-s3": "^3.1030.0",
24
- "@aws-sdk/s3-request-presigner": "^3.1030.0",
25
- "@logtape/logtape": "^1.3.7",
22
+ "@aws-sdk/client-bedrock-agent-runtime": "^3.1041.0",
23
+ "@aws-sdk/client-s3": "^3.1041.0",
24
+ "@aws-sdk/s3-request-presigner": "^3.1041.0",
25
+ "@logtape/logtape": "^1.3.8",
26
26
  "@modelcontextprotocol/sdk": "^1.29.0",
27
27
  "@octokit/rest": "^22.0.1",
28
- "axios": "^1.15.0",
29
- "zod": "^3.25.76",
30
- "@pagopa/azure-tracing": "^0.5.0",
31
- "@pagopa/dx-mcpprompts": "^0.2.7"
28
+ "axios": "^1.16.0",
29
+ "zod": "^4.4.2",
30
+ "@pagopa/azure-tracing": "^0.5.1",
31
+ "@pagopa/dx-mcpprompts": "^0.2.8"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^22.19.17",
35
35
  "@vitest/coverage-v8": "^3.2.4",
36
- "eslint": "^10.2.0",
36
+ "eslint": "^10.3.0",
37
37
  "prettier": "3.8.3",
38
38
  "tsx": "^4.21.0",
39
39
  "typescript": "~5.9.3",
40
40
  "vitest": "^3.2.4",
41
- "@pagopa/eslint-config": "^6.0.3"
41
+ "@pagopa/eslint-config": "^6.0.4"
42
42
  },
43
43
  "scripts": {
44
44
  "start": "tsx src/cli.ts",