@pagopa/dx-mcpserver 0.1.3 → 0.1.5

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.
@@ -167,12 +167,6 @@ describe("HTTP Endpoints Integration Tests", () => {
167
167
  expect(data).toHaveProperty("query");
168
168
  expect(data).toHaveProperty("results");
169
169
  expect(Array.isArray(data.results)).toBe(true);
170
- if (data.results.length > 0) {
171
- const result = data.results[0];
172
- expect(result).toHaveProperty("content");
173
- expect(result).toHaveProperty("score");
174
- expect(typeof result.score).toBe("number");
175
- }
176
170
  });
177
171
  it("should use default number_of_results when not provided", async () => {
178
172
  const response = await fetch(`${baseUrl}/search`, {
@@ -1,5 +1,51 @@
1
1
  import { describe, expect, it, vi } from "vitest";
2
- import { mockCatalogEntry, mockPromptEntry, mockTool, } from "./__mocks__/handlers.js";
2
+ import { z } from "zod";
3
+ export const mockTool = {
4
+ annotations: {
5
+ destructiveHint: false,
6
+ idempotentHint: true,
7
+ openWorldHint: true,
8
+ readOnlyHint: true,
9
+ title: "Test Tool",
10
+ },
11
+ description: "A test tool",
12
+ execute: vi.fn(async (args) => {
13
+ const parsedResult = z.object({ input: z.string() }).safeParse(args);
14
+ if (!parsedResult.success) {
15
+ return "Error: Invalid input";
16
+ }
17
+ return `Tool executed with: ${parsedResult.data.input}`;
18
+ }),
19
+ name: "TestTool",
20
+ parameters: z.object({
21
+ input: z.string().min(1, "Input cannot be empty"),
22
+ }),
23
+ };
24
+ export const mockCatalogEntry = {
25
+ category: "test",
26
+ enabled: true,
27
+ id: "test-prompt",
28
+ metadata: {
29
+ description: "A test prompt for unit testing",
30
+ title: "Test Prompt",
31
+ },
32
+ prompt: {
33
+ arguments: [
34
+ { description: "First argument", name: "arg1", required: true },
35
+ { description: "Second argument", name: "arg2", required: false },
36
+ ],
37
+ description: "A test prompt",
38
+ load: async (args) => `Prompt loaded with args: ${JSON.stringify(args)}`,
39
+ name: "TestPrompt",
40
+ },
41
+ tags: ["test"],
42
+ };
43
+ export const mockPromptEntry = {
44
+ catalogEntry: mockCatalogEntry,
45
+ prompt: {
46
+ load: vi.fn(async (args) => `Prompt loaded with args: ${JSON.stringify(args)}`),
47
+ },
48
+ };
3
49
  describe("MCP Server Handlers", () => {
4
50
  describe("Tool Handler Validation", () => {
5
51
  it("should validate tool arguments against the Zod schema", async () => {
@@ -11,9 +57,7 @@ describe("MCP Server Handlers", () => {
11
57
  const invalidArgs = { input: "" };
12
58
  const invalidationResult = mockTool.parameters.safeParse(invalidArgs);
13
59
  expect(invalidationResult.success).toBe(false);
14
- if (!invalidationResult.success) {
15
- expect(invalidationResult.error.issues[0].message).toContain("cannot be empty");
16
- }
60
+ expect(invalidationResult.error?.issues[0].message).toContain("cannot be empty");
17
61
  });
18
62
  it("should handle tool execution errors gracefully", async () => {
19
63
  const errorTool = {
@@ -125,11 +125,8 @@ describe("queryKnowledgeBaseStructured - Basic Functionality", () => {
125
125
  const result = await queryKnowledgeBaseStructured("kbId", "query", mockClient);
126
126
  // resolveToWebsiteUrl should transform S3 URI to website URL
127
127
  expect(result[0].location).toBeDefined();
128
- if (result[0].location?.webLocation?.url) {
129
- expect(result[0].location.webLocation.url).toContain("https://");
130
- // URL should have /index removed
131
- expect(result[0].location.webLocation.url).not.toContain("/index");
132
- }
128
+ expect(result[0].location?.webLocation?.url).toContain("https://");
129
+ expect(result[0].location?.webLocation?.url).not.toContain("/index");
133
130
  });
134
131
  it("should skip image content with warning logs", async () => {
135
132
  const mockClient = createMockBedrockClient(vi.fn().mockResolvedValue({
@@ -155,7 +155,7 @@ export function resolveToWebsiteUrl(location) {
155
155
  const match = location.s3Location.uri.match(/^s3:\/\/(?:[^/]+)\/(.+)$/);
156
156
  if (match) {
157
157
  const key = match[1];
158
- let url = "";
158
+ let url;
159
159
  // Special case: llms-full.txt or llms.txt should be returned as https://dx.pagopa.it/<file>
160
160
  if (key === "llms-full.txt" || key === "llms.txt") {
161
161
  url = `https://dx.pagopa.it/${key}`;
@@ -22,18 +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
- if (!result.success) {
26
- expect(result.error.errors[0].message).toBe("Query must be at least 3 characters");
27
- }
25
+ expect(result.error?.errors[0].message).toBe("Query must be at least 3 characters");
28
26
  });
29
27
  });
30
28
  it("should reject queries exceeding 500 characters", () => {
31
29
  const longQuery = { query: "a".repeat(501) };
32
30
  const result = queryDocSchema.safeParse(longQuery);
33
31
  expect(result.success).toBe(false);
34
- if (!result.success) {
35
- expect(result.error.errors[0].message).toBe("Query must not exceed 500 characters");
36
- }
32
+ expect(result.error?.errors[0].message).toBe("Query must not exceed 500 characters");
37
33
  });
38
34
  it("should reject missing query field", () => {
39
35
  const missingQuery = {};
@@ -45,23 +45,6 @@ describe("Tool Registry", () => {
45
45
  expect(entry.tool.annotations.title).toBeTruthy();
46
46
  }
47
47
  });
48
- it("should have boolean values for hint annotations when defined", () => {
49
- for (const entry of toolDefinitions) {
50
- const { annotations } = entry.tool;
51
- if (annotations.readOnlyHint !== undefined) {
52
- expect(annotations.readOnlyHint).toBeTypeOf("boolean");
53
- }
54
- if (annotations.destructiveHint !== undefined) {
55
- expect(annotations.destructiveHint).toBeTypeOf("boolean");
56
- }
57
- if (annotations.idempotentHint !== undefined) {
58
- expect(annotations.idempotentHint).toBeTypeOf("boolean");
59
- }
60
- if (annotations.openWorldHint !== undefined) {
61
- expect(annotations.openWorldHint).toBeTypeOf("boolean");
62
- }
63
- }
64
- });
65
48
  });
66
49
  describe("session requirements", () => {
67
50
  it("should mark documentation tool as not requiring session", () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/dx-mcpserver",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "An MCP server that supports developers using DX tools.",
6
6
  "repository": {
@@ -22,23 +22,23 @@
22
22
  "@aws-sdk/client-bedrock-agent-runtime": "^3.583.0",
23
23
  "@aws-sdk/client-s3": "^3.583.0",
24
24
  "@aws-sdk/s3-request-presigner": "^3.583.0",
25
- "@logtape/logtape": "^1.3.4",
25
+ "@logtape/logtape": "^1.3.7",
26
26
  "@modelcontextprotocol/sdk": "^1.26.0",
27
- "@octokit/rest": "^22.0.0",
28
- "axios": "^1.12.2",
27
+ "@octokit/rest": "^22.0.1",
28
+ "axios": "^1.13.6",
29
29
  "zod": "^3.25.76",
30
- "@pagopa/azure-tracing": "^0.4.11",
31
- "@pagopa/dx-mcpprompts": "^0.2.2"
30
+ "@pagopa/azure-tracing": "^0.4.13",
31
+ "@pagopa/dx-mcpprompts": "^0.2.5"
32
32
  },
33
33
  "devDependencies": {
34
- "@types/node": "^22.19.1",
34
+ "@types/node": "^22.19.15",
35
35
  "@vitest/coverage-v8": "^3.2.4",
36
- "eslint": "^9.39.2",
37
- "prettier": "3.6.2",
38
- "tsx": "^4.20.6",
39
- "typescript": "~5.8.3",
36
+ "eslint": "^10.1.0",
37
+ "prettier": "3.8.1",
38
+ "tsx": "^4.21.0",
39
+ "typescript": "~5.9.3",
40
40
  "vitest": "^3.2.4",
41
- "@pagopa/eslint-config": "^5.1.2"
41
+ "@pagopa/eslint-config": "^6.0.0"
42
42
  },
43
43
  "scripts": {
44
44
  "start": "tsx src/cli.ts",
@@ -1,48 +0,0 @@
1
- import { vi } from "vitest";
2
- import { z } from "zod";
3
- export const mockTool = {
4
- annotations: {
5
- destructiveHint: false,
6
- idempotentHint: true,
7
- openWorldHint: true,
8
- readOnlyHint: true,
9
- title: "Test Tool",
10
- },
11
- description: "A test tool",
12
- execute: vi.fn(async (args) => {
13
- const parsedResult = z.object({ input: z.string() }).safeParse(args);
14
- if (!parsedResult.success) {
15
- return "Error: Invalid input";
16
- }
17
- return `Tool executed with: ${parsedResult.data.input}`;
18
- }),
19
- name: "TestTool",
20
- parameters: z.object({
21
- input: z.string().min(1, "Input cannot be empty"),
22
- }),
23
- };
24
- export const mockCatalogEntry = {
25
- category: "test",
26
- enabled: true,
27
- id: "test-prompt",
28
- metadata: {
29
- description: "A test prompt for unit testing",
30
- title: "Test Prompt",
31
- },
32
- prompt: {
33
- arguments: [
34
- { description: "First argument", name: "arg1", required: true },
35
- { description: "Second argument", name: "arg2", required: false },
36
- ],
37
- description: "A test prompt",
38
- load: async (args) => `Prompt loaded with args: ${JSON.stringify(args)}`,
39
- name: "TestPrompt",
40
- },
41
- tags: ["test"],
42
- };
43
- export const mockPromptEntry = {
44
- catalogEntry: mockCatalogEntry,
45
- prompt: {
46
- load: vi.fn(async (args) => `Prompt loaded with args: ${JSON.stringify(args)}`),
47
- },
48
- };