Skip to main content
Glama

Promptopia MCP

by lumile
MIT License
18
2
tools-handler.test.ts16 kB
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest' import { ToolsHandler } from '../src/handlers/tools.handler.js' import { fileURLToPath } from 'url' import path from 'path' import fs from 'fs/promises' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) const TEST_PROMPTS_DIR = path.join(__dirname, '..', 'test-prompts-tools') describe('ToolsHandler Multi-Message Support', () => { let toolsHandler: ToolsHandler beforeAll(async () => { // Create test prompts directory await fs.mkdir(TEST_PROMPTS_DIR, { recursive: true }) // Initialize handler with test directory process.env.PROMPTS_DIR = TEST_PROMPTS_DIR toolsHandler = new ToolsHandler() }) beforeEach(async () => { // Clean up any existing test files before each test try { const files = await fs.readdir(TEST_PROMPTS_DIR) for (const file of files) { if (file.endsWith('.json')) { await fs.unlink(path.join(TEST_PROMPTS_DIR, file)) } } } catch (error) { // Directory might be empty, that's fine } }) afterAll(async () => { // Clean up test prompts directory await fs.rm(TEST_PROMPTS_DIR, { recursive: true, force: true }) }) describe('Tool Schema Validation', () => { it('should list all tools including new multi-message tools', () => { const result = toolsHandler.listTools() expect(result.tools).toBeDefined() expect(Array.isArray(result.tools)).toBe(true) const toolNames = result.tools.map(tool => tool.name) expect(toolNames).toContain('add_prompt') expect(toolNames).toContain('add_multi_message_prompt') expect(toolNames).toContain('update_prompt') expect(toolNames).toContain('get_prompt') expect(toolNames).toContain('list_prompts') expect(toolNames).toContain('delete_prompt') expect(toolNames).toContain('apply_prompt') }) it('should have correct schema for add_multi_message_prompt tool', () => { const result = toolsHandler.listTools() const tool = result.tools.find(t => t.name === 'add_multi_message_prompt') expect(tool).toBeDefined() expect(tool!.description).toContain('multi-message prompt') expect(tool!.inputSchema.type).toBe('object') expect(tool!.inputSchema.required).toEqual(['name', 'messages']) const properties = tool!.inputSchema.properties expect(properties.name).toBeDefined() expect(properties.description).toBeDefined() expect(properties.messages).toBeDefined() expect(properties.messages.type).toBe('array') expect(properties.messages.items.type).toBe('object') expect(properties.messages.items.required).toEqual(['role', 'content']) }) it('should have updated schema for update_prompt tool', () => { const result = toolsHandler.listTools() const tool = result.tools.find(t => t.name === 'update_prompt') expect(tool).toBeDefined() expect(tool!.description).toContain('both single content and multi-message formats') expect(tool!.inputSchema.required).toEqual(['id']) const properties = tool!.inputSchema.properties expect(properties.id).toBeDefined() expect(properties.name).toBeDefined() expect(properties.description).toBeDefined() expect(properties.messages).toBeDefined() expect(properties.messages.type).toBe('array') // Should not have 'content' property anymore expect(properties.content).toBeUndefined() }) }) describe('add_multi_message_prompt Tool', () => { it('should create multi-message prompt successfully', async () => { const result = await toolsHandler.callTool('add_multi_message_prompt', { name: 'Test Multi Prompt', description: 'A test multi-message prompt', messages: [ { role: 'assistant', content: { type: 'text', text: 'You are a helpful assistant for {{task}}.' } }, { role: 'user', content: { type: 'text', text: 'Please help me with {{request}}.' } } ] }) expect(result.content).toHaveLength(1) expect(result.content[0].type).toBe('text') const promptData = JSON.parse(result.content[0].text) expect(promptData.id).toMatch(/^prompt-[a-f0-9]{8}$/) expect(promptData.name).toBe('Test Multi Prompt') expect(promptData.description).toBe('A test multi-message prompt') expect(promptData.version).toBe('2.0') expect(promptData.variables).toEqual(['task', 'request']) expect(promptData.messages).toHaveLength(2) expect(promptData.createdAt).toBeDefined() }) it('should create multi-message prompt with image content', async () => { const result = await toolsHandler.callTool('add_multi_message_prompt', { name: 'Image Prompt', messages: [ { role: 'user', content: { type: 'image', image: 'base64encodedimage' } }, { role: 'assistant', content: { type: 'text', text: 'I can see the image you shared.' } } ] }) const promptData = JSON.parse(result.content[0].text) expect(promptData.messages[0].content.type).toBe('image') expect(promptData.messages[0].content.image).toBe('base64encodedimage') expect(promptData.messages[1].content.type).toBe('text') expect(promptData.variables).toEqual([]) }) it('should handle optional description parameter', async () => { const result = await toolsHandler.callTool('add_multi_message_prompt', { name: 'No Description Prompt', messages: [ { role: 'user', content: { type: 'text', text: 'Simple message' } } ] }) const promptData = JSON.parse(result.content[0].text) expect(promptData.description).toBe('') }) it('should reject invalid message structure', async () => { await expect(toolsHandler.callTool('add_multi_message_prompt', { name: 'Invalid Prompt', messages: [ { role: 'invalid-role', content: { type: 'text', text: 'Message' } } ] })).rejects.toThrow() }) it('should reject empty messages array', async () => { await expect(toolsHandler.callTool('add_multi_message_prompt', { name: 'Empty Messages', messages: [] })).rejects.toThrow() }) }) describe('Enhanced update_prompt Tool', () => { it('should update multi-message prompt', async () => { // First create a multi-message prompt const createResult = await toolsHandler.callTool('add_multi_message_prompt', { name: 'Original Prompt', description: 'Original description', messages: [ { role: 'user', content: { type: 'text', text: 'Original message' } } ] }) const originalData = JSON.parse(createResult.content[0].text) // Update the prompt const updateResult = await toolsHandler.callTool('update_prompt', { id: originalData.id, name: 'Updated Prompt', description: 'Updated description', messages: [ { role: 'assistant', content: { type: 'text', text: 'Assistant context for {{topic}}' } }, { role: 'user', content: { type: 'text', text: 'Updated message about {{topic}}' } } ] }) const updateData = JSON.parse(updateResult.content[0].text) expect(updateData.success).toBe(true) expect(updateData.prompt.name).toBe('Updated Prompt') expect(updateData.prompt.description).toBe('Updated description') expect(updateData.prompt.version).toBe('2.0') expect(updateData.prompt.messages).toHaveLength(2) expect(updateData.prompt.variables).toEqual(['topic']) }) it('should convert single content prompt to multi-message', async () => { // First create a single content prompt const createResult = await toolsHandler.callTool('add_prompt', { name: 'Single Content', content: 'Hello {{name}}!', description: 'Simple greeting' }) const originalData = JSON.parse(createResult.content[0].text) // Convert to multi-message const updateResult = await toolsHandler.callTool('update_prompt', { id: originalData.id, name: 'Multi-Message Greeting', messages: [ { role: 'assistant', content: { type: 'text', text: 'You are a friendly greeter.' } }, { role: 'user', content: { type: 'text', text: 'Greet {{name}} in a {{style}} manner.' } } ] }) const updateData = JSON.parse(updateResult.content[0].text) expect(updateData.success).toBe(true) expect(updateData.prompt.version).toBe('2.0') expect(updateData.prompt.messages).toHaveLength(2) expect(updateData.prompt.variables).toEqual(['name', 'style']) }) it('should update single content prompt without conversion', async () => { // Create single content prompt const createResult = await toolsHandler.callTool('add_prompt', { name: 'Single Content', content: 'Original content', description: 'Original' }) const originalData = JSON.parse(createResult.content[0].text) // Update without messages (keep single content format) const updateResult = await toolsHandler.callTool('update_prompt', { id: originalData.id, name: 'Updated Single', description: 'Updated description' }) const updateData = JSON.parse(updateResult.content[0].text) expect(updateData.success).toBe(true) expect(updateData.prompt.name).toBe('Updated Single') expect(updateData.prompt.description).toBe('Updated description') expect(updateData.prompt.content).toBe('Original content') expect(updateData.prompt.version).toBeUndefined() }) }) describe('Enhanced apply_prompt Tool', () => { it('should apply variables to multi-message prompt and return structured data', async () => { // Create multi-message prompt const createResult = await toolsHandler.callTool('add_multi_message_prompt', { name: 'Code Assistant', messages: [ { role: 'assistant', content: { type: 'text', text: 'You are a {{language}} coding assistant.' } }, { role: 'user', content: { type: 'text', text: 'Help me write {{language}} code for {{task}}.' } } ] }) const promptData = JSON.parse(createResult.content[0].text) // Apply variables const applyResult = await toolsHandler.callTool('apply_prompt', { id: promptData.id, variables: { language: 'Python', task: 'data analysis' } }) expect(applyResult.content[0].type).toBe('text') const resultText = applyResult.content[0].text // Should return JSON for multi-message prompts expect(() => JSON.parse(resultText)).not.toThrow() const appliedMessages = JSON.parse(resultText) expect(appliedMessages).toHaveLength(2) expect(appliedMessages[0].content.text).toBe('You are a Python coding assistant.') expect(appliedMessages[1].content.text).toBe('Help me write Python code for data analysis.') }) it('should apply variables to single content prompt and return text', async () => { // Create single content prompt const createResult = await toolsHandler.callTool('add_prompt', { name: 'Simple Task', content: 'Complete the {{task}} using {{method}}.' }) const promptData = JSON.parse(createResult.content[0].text) // Apply variables const applyResult = await toolsHandler.callTool('apply_prompt', { id: promptData.id, variables: { task: 'calculation', method: 'calculator' } }) expect(applyResult.content[0].type).toBe('text') expect(applyResult.content[0].text).toBe('Complete the calculation using calculator.') }) it('should handle missing variables error', async () => { // Create prompt with variables const createResult = await toolsHandler.callTool('add_multi_message_prompt', { name: 'Required Variables', messages: [ { role: 'user', content: { type: 'text', text: 'Need {{required}} variable' } } ] }) const promptData = JSON.parse(createResult.content[0].text) // Try to apply without required variables await expect(toolsHandler.callTool('apply_prompt', { id: promptData.id, variables: {} })).rejects.toThrow('Missing required variables: required') }) }) describe('Backward Compatibility', () => { it('should maintain existing tool functionality', async () => { // Test existing add_prompt tool const result = await toolsHandler.callTool('add_prompt', { name: 'Legacy Prompt', content: 'Legacy content with {{var}}', description: 'Legacy description' }) const promptData = JSON.parse(result.content[0].text) expect(promptData.content).toBe('Legacy content with {{var}}') expect(promptData.variables).toEqual(['var']) expect(promptData.version).toBeUndefined() // Test list_prompts const listResult = await toolsHandler.callTool('list_prompts', {}) const listData = JSON.parse(listResult.content[0].text) expect(listData.prompts).toHaveLength(1) expect(listData.prompts[0].name).toBe('Legacy Prompt') // Test get_prompt const getResult = await toolsHandler.callTool('get_prompt', { id: promptData.id }) const getData = JSON.parse(getResult.content[0].text) expect(getData.name).toBe('Legacy Prompt') // Test delete_prompt const deleteResult = await toolsHandler.callTool('delete_prompt', { id: promptData.id }) const deleteData = JSON.parse(deleteResult.content[0].text) expect(deleteData.success).toBe(true) }) it('should handle mixed prompt formats in listing', async () => { // Create both formats await toolsHandler.callTool('add_prompt', { name: 'Single Format', content: 'Single content' }) await toolsHandler.callTool('add_multi_message_prompt', { name: 'Multi Format', messages: [ { role: 'user', content: { type: 'text', text: 'Multi content' } } ] }) // List all prompts const listResult = await toolsHandler.callTool('list_prompts', {}) const listData = JSON.parse(listResult.content[0].text) expect(listData.prompts).toHaveLength(2) const singlePrompt = listData.prompts.find((p: any) => p.name === 'Single Format') const multiPrompt = listData.prompts.find((p: any) => p.name === 'Multi Format') expect(singlePrompt.content).toBeDefined() expect(singlePrompt.version).toBeUndefined() expect(multiPrompt.messages).toBeDefined() expect(multiPrompt.version).toBe('2.0') }) }) })

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lumile/promptopia-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server