tests
This commit is contained in:
parent
2d61b4b8fc
commit
c088719985
1 changed files with 182 additions and 217 deletions
|
|
@ -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."
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue