From c08871998530d3f5f10e53d52342c645e2a73230 Mon Sep 17 00:00:00 2001 From: ihrpr Date: Tue, 10 Jun 2025 17:26:48 +0100 Subject: [PATCH] tests --- src/server/mcp.test.ts | 393 +++++++++++++++++++---------------------- 1 file changed, 179 insertions(+), 214 deletions(-) diff --git a/src/server/mcp.test.ts b/src/server/mcp.test.ts index bcf09d52..7cb0c489 100644 --- a/src/server/mcp.test.ts +++ b/src/server/mcp.test.ts @@ -3458,258 +3458,223 @@ describe("prompt()", () => { expect(typeof receivedRequestId === 'string' || typeof receivedRequestId === 'number').toBe(true); expect(result.messages[0].content.text).toContain("Received request ID:"); }); +}); - /** - * Test: Restaurant booking example with elicitation from README - */ - describe("Restaurant booking elicitation example", () => { - // Mock restaurant booking functions - const checkAvailability = jest.fn().mockResolvedValue(false); - const findAlternatives = jest.fn().mockResolvedValue([]); - const makeBooking = jest.fn().mockResolvedValue("BOOKING-123"); +describe("elicitInput()", () => { - let mcpServer: McpServer; - let client: Client; + const checkAvailability = jest.fn().mockResolvedValue(false); + const findAlternatives = jest.fn().mockResolvedValue([]); + const makeBooking = jest.fn().mockResolvedValue("BOOKING-123"); - beforeEach(() => { - // Reset mocks - jest.clearAllMocks(); - - // Create server with restaurant booking tool - mcpServer = new McpServer({ - name: "restaurant-booking-server", - version: "1.0.0", - }); + let mcpServer: McpServer; + let client: Client; - // Register the restaurant booking tool from README example - mcpServer.tool( - "book-restaurant", - { - restaurant: z.string(), - date: z.string(), - partySize: z.number() - }, - async ({ restaurant, date, partySize }) => { - // Check availability - const available = await checkAvailability(restaurant, date, partySize); - - if (!available) { - // Ask user if they want to try alternative dates - const result = await mcpServer.server.elicitInput({ - message: `No tables available at ${restaurant} on ${date}. Would you like to check alternative dates?`, - requestedSchema: { - type: "object", - properties: { - checkAlternatives: { - type: "boolean", - title: "Check alternative dates", - description: "Would you like me to check other dates?" - }, - flexibleDates: { - type: "string", - title: "Date flexibility", - description: "How flexible are your dates?", - enum: ["next_day", "same_week", "next_week"], - enumNames: ["Next day", "Same week", "Next week"] - } + beforeEach(() => { + jest.clearAllMocks(); + + // Create server with restaurant booking tool + mcpServer = new McpServer({ + name: "restaurant-booking-server", + version: "1.0.0", + }); + + // Register the restaurant booking tool from README example + mcpServer.tool( + "book-restaurant", + { + restaurant: z.string(), + date: z.string(), + partySize: z.number() + }, + async ({ restaurant, date, partySize }) => { + // Check availability + const available = await checkAvailability(restaurant, date, partySize); + + if (!available) { + // Ask user if they want to try alternative dates + const result = await mcpServer.server.elicitInput({ + message: `No tables available at ${restaurant} on ${date}. Would you like to check alternative dates?`, + requestedSchema: { + type: "object", + properties: { + checkAlternatives: { + type: "boolean", + title: "Check alternative dates", + description: "Would you like me to check other dates?" }, - required: ["checkAlternatives"] - } - }); - - if (result.action === "accept" && result.content?.checkAlternatives) { - const alternatives = await findAlternatives( - restaurant, - date, - partySize, - result.content.flexibleDates as string - ); - return { - content: [{ - type: "text", - text: `Found these alternatives: ${alternatives.join(", ")}` - }] - }; + flexibleDates: { + type: "string", + title: "Date flexibility", + description: "How flexible are your dates?", + enum: ["next_day", "same_week", "next_week"], + enumNames: ["Next day", "Same week", "Next week"] + } + }, + required: ["checkAlternatives"] } - + }); + + if (result.action === "accept" && result.content?.checkAlternatives) { + const alternatives = await findAlternatives( + restaurant, + date, + partySize, + result.content.flexibleDates as string + ); return { content: [{ type: "text", - text: "No booking made. Original date not available." + text: `Found these alternatives: ${alternatives.join(", ")}` }] }; } - - // Book the table - await makeBooking(restaurant, date, partySize); + return { content: [{ type: "text", - text: `Booked table for ${partySize} at ${restaurant} on ${date}` + text: "No booking made. Original date not available." }] }; } - ); - // Create client with elicitation capability - client = new Client( - { - name: "test-client", - version: "1.0.0", + await makeBooking(restaurant, date, partySize); + return { + content: [{ + type: "text", + text: `Booked table for ${partySize} at ${restaurant} on ${date}` + }] + }; + } + ); + + // Create client with elicitation capability + client = new Client( + { + name: "test-client", + version: "1.0.0", + }, + { + capabilities: { + elicitation: {}, }, - { - capabilities: { - elicitation: {}, - }, + } + ); + }); + + test("should successfully elicit additional information", async () => { + // Mock availability check to return false + checkAvailability.mockResolvedValue(false); + findAlternatives.mockResolvedValue(["2024-12-26", "2024-12-27", "2024-12-28"]); + + // Set up client to accept alternative date checking + client.setRequestHandler(ElicitRequestSchema, async (request) => { + expect(request.params.message).toContain("No tables available at ABC Restaurant on 2024-12-25"); + return { + action: "accept", + content: { + checkAlternatives: true, + flexibleDates: "same_week" } - ); + }; }); - test("should successfully book when table is available", async () => { - // Mock availability check to return true - checkAvailability.mockResolvedValue(true); - makeBooking.mockResolvedValue("BOOKING-123"); + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); - const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); - - await Promise.all([ - client.connect(clientTransport), - mcpServer.server.connect(serverTransport), - ]); + await Promise.all([ + client.connect(clientTransport), + mcpServer.server.connect(serverTransport), + ]); - // Call the tool - const result = await client.callTool({ - name: "book-restaurant", - arguments: { - restaurant: "ABC Restaurant", - date: "2024-12-25", - partySize: 2 - } - }); - - expect(checkAvailability).toHaveBeenCalledWith("ABC Restaurant", "2024-12-25", 2); - expect(makeBooking).toHaveBeenCalledWith("ABC Restaurant", "2024-12-25", 2); - expect(result.content).toEqual([{ - type: "text", - text: "Booked table for 2 at ABC Restaurant on 2024-12-25" - }]); + // Call the tool + const result = await client.callTool({ + name: "book-restaurant", + arguments: { + restaurant: "ABC Restaurant", + date: "2024-12-25", + partySize: 2 + } }); - test("should ask for alternatives when no availability and user accepts", async () => { - // Mock availability check to return false - checkAvailability.mockResolvedValue(false); - findAlternatives.mockResolvedValue(["2024-12-26", "2024-12-27", "2024-12-28"]); + expect(checkAvailability).toHaveBeenCalledWith("ABC Restaurant", "2024-12-25", 2); + expect(findAlternatives).toHaveBeenCalledWith("ABC Restaurant", "2024-12-25", 2, "same_week"); + expect(result.content).toEqual([{ + type: "text", + text: "Found these alternatives: 2024-12-26, 2024-12-27, 2024-12-28" + }]); + }); - // Set up client to accept alternative date checking - client.setRequestHandler(ElicitRequestSchema, async (request) => { - expect(request.params.message).toContain("No tables available at ABC Restaurant on 2024-12-25"); - return { - action: "accept", - content: { - checkAlternatives: true, - flexibleDates: "same_week" - } - }; - }); + test("should handle user declining to elicitation request", async () => { + // Mock availability check to return false + checkAvailability.mockResolvedValue(false); - const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); - - await Promise.all([ - client.connect(clientTransport), - mcpServer.server.connect(serverTransport), - ]); - - // Call the tool - const result = await client.callTool({ - name: "book-restaurant", - arguments: { - restaurant: "ABC Restaurant", - date: "2024-12-25", - partySize: 2 + // Set up client to decline alternative date checking + client.setRequestHandler(ElicitRequestSchema, async () => { + return { + action: "accept", + content: { + checkAlternatives: false } - }); - - expect(checkAvailability).toHaveBeenCalledWith("ABC Restaurant", "2024-12-25", 2); - expect(findAlternatives).toHaveBeenCalledWith("ABC Restaurant", "2024-12-25", 2, "same_week"); - expect(result.content).toEqual([{ - type: "text", - text: "Found these alternatives: 2024-12-26, 2024-12-27, 2024-12-28" - }]); + }; }); - test("should handle user declining to check alternatives", async () => { - // Mock availability check to return false - checkAvailability.mockResolvedValue(false); + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); - // Set up client to decline alternative date checking - client.setRequestHandler(ElicitRequestSchema, async () => { - return { - action: "accept", - content: { - checkAlternatives: false - } - }; - }); + await Promise.all([ + client.connect(clientTransport), + mcpServer.server.connect(serverTransport), + ]); - const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); - - await Promise.all([ - client.connect(clientTransport), - mcpServer.server.connect(serverTransport), - ]); - - // Call the tool - const result = await client.callTool({ - name: "book-restaurant", - arguments: { - restaurant: "ABC Restaurant", - date: "2024-12-25", - partySize: 2 - } - }); - - expect(checkAvailability).toHaveBeenCalledWith("ABC Restaurant", "2024-12-25", 2); - expect(findAlternatives).not.toHaveBeenCalled(); - expect(result.content).toEqual([{ - type: "text", - text: "No booking made. Original date not available." - }]); + // Call the tool + const result = await client.callTool({ + name: "book-restaurant", + arguments: { + restaurant: "ABC Restaurant", + date: "2024-12-25", + partySize: 2 + } }); - test("should handle user cancelling the elicitation", async () => { - // Mock availability check to return false - checkAvailability.mockResolvedValue(false); + expect(checkAvailability).toHaveBeenCalledWith("ABC Restaurant", "2024-12-25", 2); + expect(findAlternatives).not.toHaveBeenCalled(); + expect(result.content).toEqual([{ + type: "text", + text: "No booking made. Original date not available." + }]); + }); - // Set up client to cancel the elicitation - client.setRequestHandler(ElicitRequestSchema, async () => { - return { - action: "cancel" - }; - }); + test("should handle user cancelling the elicitation", async () => { + // Mock availability check to return false + checkAvailability.mockResolvedValue(false); - const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); - - await Promise.all([ - client.connect(clientTransport), - mcpServer.server.connect(serverTransport), - ]); - - // Call the tool - const result = await client.callTool({ - name: "book-restaurant", - arguments: { - restaurant: "ABC Restaurant", - date: "2024-12-25", - partySize: 2 - } - }); - - expect(checkAvailability).toHaveBeenCalledWith("ABC Restaurant", "2024-12-25", 2); - expect(findAlternatives).not.toHaveBeenCalled(); - expect(result.content).toEqual([{ - type: "text", - text: "No booking made. Original date not available." - }]); + // Set up client to cancel the elicitation + client.setRequestHandler(ElicitRequestSchema, async () => { + return { + action: "cancel" + }; }); + + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); + + await Promise.all([ + client.connect(clientTransport), + mcpServer.server.connect(serverTransport), + ]); + + // Call the tool + const result = await client.callTool({ + name: "book-restaurant", + arguments: { + restaurant: "ABC Restaurant", + date: "2024-12-25", + partySize: 2 + } + }); + + expect(checkAvailability).toHaveBeenCalledWith("ABC Restaurant", "2024-12-25", 2); + expect(findAlternatives).not.toHaveBeenCalled(); + expect(result.content).toEqual([{ + type: "text", + text: "No booking made. Original date not available." + }]); }); });