Code Snippet Server

by ngeojiajun
Verified
import { jest, describe, it, expect, beforeEach, afterEach, } from "@jest/globals"; import type { SystempromptPromptResponse, SystempromptBlockResponse, } from "../../types/index.js"; import type { CallToolRequest, CallToolResult, Tool, } from "@modelcontextprotocol/sdk/types.js"; import type { gmail_v1 } from "googleapis/build/src/apis/gmail/v1.js"; import { calendar_v3 } from "googleapis/build/src/apis/calendar/v3.js"; import type { EmailMetadata } from "../../services/gmail-service"; // Mock process.exit const mockExit = jest .spyOn(process, "exit") .mockImplementation(() => undefined as never); // Mock the SDK modules jest.mock("@modelcontextprotocol/sdk/server/stdio.js", () => ({ __esModule: true, StdioServerTransport: jest.fn(() => ({ start: jest.fn(), stop: jest.fn(), onRequest: jest.fn(), })), })); jest.mock("@modelcontextprotocol/sdk/server/index.js", () => ({ __esModule: true, Server: jest.fn(() => ({ start: jest.fn(), stop: jest.fn(), onRequest: jest.fn(), registerHandler: jest.fn(), registerHandlers: jest.fn(), })), })); jest.mock("@modelcontextprotocol/sdk/types.js", () => ({ __esModule: true, ListToolsRequest: jest.fn(), CallToolRequest: jest.fn(), })); // Mock the index module jest.mock("../../index.js", () => ({ __esModule: true, server: { notification: jest.fn(), }, })); // Mock Gmail Service jest.mock("../../services/gmail-service", () => { const mockEmailMetadata: EmailMetadata = { id: "123", threadId: "456", snippet: "", from: { email: "test@example.com" }, to: [{ email: "to@example.com" }], subject: "Test", date: new Date(), labels: [], hasAttachments: false, isUnread: false, isImportant: false, }; const mockGmailMessage = { ...mockEmailMetadata, body: "test", }; const mockGmailService = { listMessages: jest.fn(() => Promise.resolve([mockEmailMetadata])), getMessage: jest.fn(() => Promise.resolve(mockGmailMessage)), searchMessages: jest.fn(() => Promise.resolve([{ ...mockEmailMetadata, id: "789", threadId: "012" }]) ), getLabels: jest.fn(() => Promise.resolve([ { id: "label1", name: "INBOX" }, ] as gmail_v1.Schema$Label[]) ), sendEmail: jest.fn(() => Promise.resolve("msg123")), createDraft: jest.fn(() => Promise.resolve("draft123")), listDrafts: jest.fn(() => Promise.resolve([{ ...mockEmailMetadata, id: "draft1" }]) ), deleteDraft: jest.fn(() => Promise.resolve()), }; return { __esModule: true, GmailService: jest.fn(() => mockGmailService), }; }); // Mock Calendar Service jest.mock("../../services/calendar-service", () => { const mockEvent: calendar_v3.Schema$Event = { id: "123", summary: "Test Event", description: "Test Description", start: { dateTime: new Date().toISOString() }, end: { dateTime: new Date().toISOString() }, attendees: [{ email: "test@example.com" }], location: "Test Location", }; const mockCalendarService = { listEvents: jest.fn(() => Promise.resolve([mockEvent])), getEvent: jest.fn(() => Promise.resolve(mockEvent)), searchEvents: jest.fn(() => Promise.resolve([mockEvent])), listCalendars: jest.fn(() => Promise.resolve([ { id: "primary", summary: "Primary Calendar" }, ] as calendar_v3.Schema$CalendarListEntry[]) ), }; return { __esModule: true, CalendarService: jest.fn(() => mockCalendarService), }; }); describe("Tool Handlers", () => { let handleListTools: any; let handleToolCall: any; beforeEach(async () => { const mockPrompt: SystempromptPromptResponse = { id: "1", metadata: { title: "Test Prompt", description: "Test Description", created: "2024-01-14", updated: "2024-01-14", version: 1, status: "active", author: "test", log_message: "test", }, instruction: { static: "test", dynamic: "test", state: "test", }, input: { name: "test", description: "test", type: ["string"], schema: {}, }, output: { name: "test", description: "test", type: ["string"], schema: {}, }, _link: "test", }; const mockBlock: SystempromptBlockResponse = { id: "1", content: "Test content", prefix: "test", metadata: { title: "Test Block", description: null, created: "2024-01-14", updated: "2024-01-14", version: 1, status: "active", author: "test", log_message: "test", }, }; const mockService = { getAllPrompts: jest.fn().mockImplementation(async () => [mockPrompt]), listBlocks: jest.fn().mockImplementation(async () => [mockBlock]), getBlock: jest.fn().mockImplementation(async () => mockBlock), }; jest.doMock("../../services/systemprompt-service.js", () => ({ SystemPromptService: { getInstance: jest.fn().mockReturnValue(mockService), initialize: jest.fn(), }, })); // Import the handlers after mocking const handlers = await import("../tool-handlers.js"); handleListTools = handlers.handleListTools; handleToolCall = handlers.handleToolCall; }); afterEach(() => { jest.clearAllMocks(); jest.resetModules(); }); describe("handleListTools", () => { it("should return list of available tools", async () => { const request = { method: "tools/list" as const, }; const result = await handleListTools(request); expect(Array.isArray(result.tools)).toBe(true); expect(result.tools.length).toBeGreaterThan(0); // Verify the structure of each tool result.tools.forEach((tool: Tool) => { expect(tool).toMatchObject({ name: expect.stringMatching(/^systemprompt_/), description: expect.any(String), inputSchema: expect.objectContaining({ type: "object", properties: expect.any(Object), }), }); }); // Verify specific tools exist const toolNames = result.tools.map((t: Tool) => t.name); expect(toolNames).toContain("systemprompt_list_messages"); expect(toolNames).toContain("systemprompt_send_email"); expect(toolNames).toContain("systemprompt_list_events"); }); }); describe("handleToolCall", () => { it("should handle invalid tool name", async () => { const request: CallToolRequest = { method: "tools/call" as const, params: { name: "invalid_tool" as any, arguments: {}, }, }; await expect(handleToolCall(request)).rejects.toThrow( "Tool call failed: Unknown tool: invalid_tool" ); }); it("should handle service errors", async () => { // Clear module cache jest.resetModules(); // Mock the service to throw an error for this test const mockServiceWithError = { getAllPrompts: jest.fn().mockImplementation(async () => []), listBlocks: jest.fn().mockImplementation(async () => []), getBlock: jest.fn().mockImplementation(async () => { throw new Error("Service error"); }), }; // Mock the service module jest.mock( "../../services/systemprompt-service.js", () => ({ SystemPromptService: { getInstance: jest.fn().mockReturnValue(mockServiceWithError), initialize: jest.fn(), }, }), { virtual: true } ); // Re-import handlers to get fresh instance with new mock const { handleToolCall: freshHandleToolCall } = await import( "../tool-handlers.js" ); const request: CallToolRequest = { method: "tools/call" as const, params: { name: "systemprompt_fetch_resource", arguments: { uuid: "test-uuid", }, }, }; await expect(freshHandleToolCall(request)).rejects.toThrow( "Tool call failed: Service error" ); }); it("should handle fetch resource request", async () => { const request: CallToolRequest = { method: "tools/call" as const, params: { name: "systemprompt_fetch_resource", arguments: { uuid: "test-uuid", }, }, }; const result = await handleToolCall(request); expect(result.content).toEqual([ { type: "resource", resource: { uri: "resource:///block/test-uuid", text: "Test content", }, }, ]); }); }); describe("Gmail Tool Handlers", () => { it("should handle systemprompt_list_messages without filters", async () => { const request: CallToolRequest = { method: "tools/call" as const, params: { name: "systemprompt_list_messages", arguments: {}, }, }; const result = await handleToolCall(request); expect(result.content[0].text).toContain("123"); }); it("should handle systemprompt_list_messages with filters", async () => { const request: CallToolRequest = { method: "tools/call" as const, params: { name: "systemprompt_list_messages", arguments: { subject: "Test", }, }, }; const result = await handleToolCall(request); expect(result.content[0].text).toContain("789"); }); it("should handle systemprompt_get_message", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_get_message", arguments: { messageId: "123", }, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toContain("123"); }); it("should handle systemprompt_search_messages", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_search_messages", arguments: { query: "important", maxResults: 10, after: "2024-01-01", before: "2024-01-31", }, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toContain("789"); }); it("should handle systemprompt_list_labels", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_list_labels", arguments: {}, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toContain("INBOX"); }); it("should handle systemprompt_send_email", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_send_email", arguments: { to: "test@example.com", subject: "Test Email", body: "Hello World", cc: "cc@example.com", bcc: "bcc@example.com", isHtml: false, }, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toContain("msg123"); }); it("should handle systemprompt_create_draft", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_create_draft", arguments: { to: "test@example.com", subject: "Test Draft", body: "Hello World", cc: "cc@example.com", bcc: "bcc@example.com", isHtml: false, }, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toContain("draft123"); }); it("should handle systemprompt_list_drafts", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_list_drafts", arguments: { maxResults: 10, }, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toContain("draft1"); }); it("should handle systemprompt_delete_draft", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_delete_draft", arguments: { draftId: "draft123", }, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toContain("success"); }); }); describe("Calendar Tool Handlers", () => { it("should handle systemprompt_list_events", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_list_events", arguments: { calendarId: "primary", maxResults: 10, }, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toBeDefined(); }); it("should handle systemprompt_get_event", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_get_event", arguments: { eventId: "123", calendarId: "primary", }, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toBeDefined(); }); it("should handle systemprompt_search_events", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_search_events", arguments: { query: "meeting", calendarId: "primary", maxResults: 10, }, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toBeDefined(); }); it("should handle systemprompt_list_calendars", async () => { const { handleToolCall } = await import("../../handlers/tool-handlers"); const request = { method: "tools/call", params: { name: "systemprompt_list_calendars", arguments: {}, }, } as CallToolRequest; const result = await handleToolCall(request); expect(result.content[0].text).toBeDefined(); }); }); it("should ensure that tool properties are never empty or undefined", () => { const { TOOLS } = require("../tool-handlers"); TOOLS.forEach((tool: Tool) => { expect(tool.inputSchema.properties).toBeDefined(); if (tool.inputSchema.properties) { expect(Object.keys(tool.inputSchema.properties).length).toBeGreaterThan( 0 ); } }); }); });