Skip to main content
Glama

MCP Prompts Server

mcp-server.ts8.1 kB
import { APIGatewayProxyHandler, APIGatewayProxyResult } from 'aws-lambda'; import { DynamoDBAdapter } from '../adapters/aws/dynamodb-adapter'; import { S3CatalogAdapter } from '../adapters/aws/s3-adapter'; import { SQSAdapter } from '../adapters/aws/sqs-adapter'; import { PromptService } from '../core/services/prompt.service'; import { McpServer } from '../mcp/mcp-server'; import { MetricsCollector } from '../monitoring/cloudwatch-metrics'; import { ValidationError, NotFoundError, ConflictError, InternalServerError } from '../core/errors/custom-errors'; // Initialize adapters const promptRepository = new DynamoDBAdapter(process.env.PROMPTS_TABLE!); const catalogRepository = new S3CatalogAdapter(process.env.PROMPTS_BUCKET!); const eventBus = new SQSAdapter(process.env.PROCESSING_QUEUE!); const metricsCollector = new MetricsCollector(); // Initialize services const promptService = new PromptService(promptRepository, catalogRepository, eventBus); const mcpServer = new McpServer(promptService); // Helper function to create error responses function createErrorResponse(error: any): { statusCode: number; body: string } { let statusCode = 500; let message = 'Internal server error'; if (error instanceof ValidationError) { statusCode = 400; message = error.message; } else if (error instanceof NotFoundError) { statusCode = 404; message = error.message; } else if (error instanceof ConflictError) { statusCode = 409; message = error.message; } else if (error instanceof InternalServerError) { statusCode = 500; message = error.message; } else if (error.message) { message = error.message; } return { statusCode, body: JSON.stringify({ error: message, type: error.name || 'UnknownError' }) }; } export const handler: APIGatewayProxyHandler = async (event, context): Promise<APIGatewayProxyResult> => { const startTime = Date.now(); try { console.log('Received event:', JSON.stringify(event, null, 2)); const { httpMethod, path, pathParameters, queryStringParameters, body } = event; // CORS headers const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token', 'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,OPTIONS' }; // Handle OPTIONS requests if (httpMethod === 'OPTIONS') { return { statusCode: 200, headers: corsHeaders, body: '' }; } let response: any; // Route requests if (path === '/health') { response = await handleHealthCheck(); } else if (path.startsWith('/v1/prompts')) { response = await handlePromptsApi(httpMethod, path, pathParameters, queryStringParameters, body); } else if (path.startsWith('/mcp')) { response = await handleMcpApi(httpMethod, path, pathParameters, queryStringParameters, body); } else { response = { statusCode: 404, body: JSON.stringify({ error: 'Not found' }) }; } // Record metrics const latency = Date.now() - startTime; await metricsCollector.recordLatency(path, latency); if (response.statusCode >= 200 && response.statusCode < 300) { await metricsCollector.recordApiSuccess(path); } else { await metricsCollector.recordApiError(path, response.statusCode); } return { ...response, headers: { ...corsHeaders, ...response.headers, 'Content-Type': 'application/json' } }; } catch (error) { console.error('Lambda error:', error); const errorResponse = createErrorResponse(error); const latency = Date.now() - startTime; await metricsCollector.recordLatency(event.path, latency); await metricsCollector.recordApiError(event.path, errorResponse.statusCode); return { statusCode: errorResponse.statusCode, headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token', 'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,OPTIONS', 'Content-Type': 'application/json' }, body: errorResponse.body }; } }; async function handleHealthCheck(): Promise<any> { const health = await Promise.all([ promptRepository.healthCheck(), catalogRepository.healthCheck(), eventBus.healthCheck() ]); const allHealthy = health.every(h => h.status === 'healthy'); return { statusCode: allHealthy ? 200 : 503, body: JSON.stringify({ status: allHealthy ? 'healthy' : 'unhealthy', services: { dynamodb: health[0], s3: health[1], sqs: health[2] }, timestamp: new Date().toISOString() }) }; } async function handlePromptsApi(method: string, path: string, pathParams: any, queryParams: any, body: string | null): Promise<any> { const parsedBody = body ? JSON.parse(body) : null; if (method === 'GET' && path === '/v1/prompts') { // List prompts const category = queryParams?.category; const limit = parseInt(queryParams?.limit || '50'); const prompts = category ? await promptService.getPromptsByCategory(category, limit) : await promptService.getLatestPrompts(limit); return { statusCode: 200, body: JSON.stringify({ prompts: prompts.map(p => p.toJSON()), total: prompts.length }) }; } if (method === 'POST' && path === '/v1/prompts') { // Create prompt const prompt = await promptService.createPrompt(parsedBody); return { statusCode: 201, body: JSON.stringify({ prompt: prompt.toJSON(), message: 'Prompt created successfully' }) }; } if (method === 'GET' && pathParams?.id) { // Get specific prompt const prompt = await promptService.getPrompt(pathParams.id); if (!prompt) { return { statusCode: 404, body: JSON.stringify({ error: 'Prompt not found' }) }; } return { statusCode: 200, body: JSON.stringify({ prompt: prompt.toJSON() }) }; } if (method === 'PUT' && pathParams?.id) { // Update prompt const prompt = await promptService.updatePrompt(pathParams.id, parsedBody); return { statusCode: 200, body: JSON.stringify({ prompt: prompt.toJSON(), message: 'Prompt updated successfully' }) }; } if (method === 'DELETE' && pathParams?.id) { // Delete prompt await promptService.deletePrompt(pathParams.id); return { statusCode: 200, body: JSON.stringify({ message: 'Prompt deleted successfully' }) }; } if (method === 'POST' && path.includes('/apply')) { // Apply template variables const promptId = pathParams?.id; const variables = parsedBody?.variables || {}; const result = await promptService.applyTemplate(promptId, variables); return { statusCode: 200, body: JSON.stringify({ result, appliedVariables: variables }) }; } return { statusCode: 405, body: JSON.stringify({ error: 'Method not allowed' }) }; } async function handleMcpApi(method: string, path: string, pathParams: any, queryParams: any, body: string | null): Promise<any> { if (method === 'GET' && path === '/mcp') { // MCP capabilities return { statusCode: 200, body: JSON.stringify(mcpServer.getCapabilities()) }; } if (method === 'GET' && path === '/mcp/tools') { // List MCP tools return { statusCode: 200, body: JSON.stringify(mcpServer.getTools()) }; } if (method === 'POST' && path === '/mcp/tools') { // Execute MCP tool const parsedBody = body ? JSON.parse(body) : null; const result = await mcpServer.executeTool(parsedBody.tool, parsedBody.arguments); return { statusCode: 200, body: JSON.stringify({ result }) }; } return { statusCode: 405, body: JSON.stringify({ error: 'Method not allowed' }) }; }

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/sparesparrow/mcp-prompts'

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