Skip to main content
Glama

AWS MCP Infrastructure

nlp.service.ts9.56 kB
import { ResourceQuery } from '../types'; import { logger } from '../utils/logger'; interface ParsedCommand { intent: 'create' | 'delete' | 'list' | 'help' | 'unknown'; resourceType?: 'ec2' | 's3' | 'dynamodb' | 'lambda' | 'iam-role'; parameters?: Record<string, any>; resourceId?: string; confidence: number; } export class NLPService { private resourcePatterns = { s3: /\b(bucket|s3|storage)\b/i, ec2: /\b(instance|server|ec2|vm|virtual machine)\b/i, dynamodb: /\b(table|dynamodb|database|db)\b/i, lambda: /\b(function|lambda|serverless)\b/i, 'iam-role': /\b(role|iam|permissions)\b/i, }; private actionPatterns = { create: /\b(create|deploy|launch|setup|configure)\b/i, delete: /\b(delete|remove|destroy)\b/i, list: /\b(show|list|get|see|display)\b/i, }; private instanceTypes = ['t2.micro', 't2.small', 't2.medium', 't2.large', 't3.micro', 't3.small']; parseNaturalLanguage(input: string): ParsedCommand { const lowerInput = input.toLowerCase(); logger.info(`Parsing natural language input: ${input}`); const intent = this.detectIntent(lowerInput); if (intent === 'list') { return { intent: 'list', confidence: 0.9 }; } if (intent === 'unknown') { return { intent: 'unknown', confidence: 0.1 }; } const resourceType = this.detectResourceType(lowerInput); if (!resourceType) { return { intent: 'unknown', confidence: 0.3 }; } const parameters = this.extractParameters(lowerInput, resourceType); let resourceId: string | undefined; if (intent === 'delete') { resourceId = this.extractResourceId(lowerInput); } return { intent, resourceType, parameters, resourceId, confidence: 0.8 }; } private detectIntent(input: string): 'create' | 'delete' | 'list' | 'unknown' { if (this.actionPatterns.create.test(input)) return 'create'; if (this.actionPatterns.delete.test(input)) return 'delete'; if (this.actionPatterns.list.test(input) && /\b(resources|all)\b/i.test(input)) return 'list'; return 'unknown'; } private detectResourceType(input: string): ParsedCommand['resourceType'] | null { for (const [type, pattern] of Object.entries(this.resourcePatterns)) { if (pattern.test(input)) { return type as ParsedCommand['resourceType']; } } return null; } private extractParameters(input: string, resourceType: string): Record<string, any> { const parameters: Record<string, any> = {}; switch (resourceType) { case 's3': parameters.bucketName = this.extractBucketName(input); parameters.environment = this.extractEnvironment(input); break; case 'ec2': parameters.instanceType = this.extractInstanceType(input) || 't2.micro'; parameters.name = this.extractResourceName(input, 'instance'); break; case 'dynamodb': parameters.tableName = this.extractTableName(input); parameters.partitionKey = this.extractPartitionKey(input) || 'id'; break; case 'lambda': parameters.functionName = this.extractResourceName(input, 'function'); parameters.runtime = this.extractRuntime(input) || 'nodejs18.x'; parameters.roleArn = 'arn:aws:iam::123456789012:role/lambda-execution-role'; break; case 'iam-role': parameters.roleName = this.extractResourceName(input, 'role'); parameters.service = this.extractService(input) || 'lambda.amazonaws.com'; break; } if (!parameters.environment) { parameters.environment = 'development'; } return parameters; } private extractBucketName(input: string): string { const patterns = [ /bucket\s+(?:named|called)?\s*["]?([a-z0-9-]+)["]?/i, /s3\s+(?:named|called)?\s*["]?([a-z0-9-]+)["]?/i, /(?:named|called)\s+["]?([a-z0-9-]+)["]?/i, /name\s+["]?([a-z0-9-]+)["]?/i, /["]([a-z0-9-]+)["]/, ]; for (const pattern of patterns) { const match = input.match(pattern); if (match && match[1]) { return match[1]; } } return `bucket-${Date.now()}`; } private extractTableName(input: string): string { const patterns = [ /table\s+(?:named|called)?\s*["]?([a-z0-9-_]+)["]?/i, /for\s+([a-z0-9-_]+)/i, /of\s+([a-z0-9-_]+)/i, ]; for (const pattern of patterns) { const match = input.match(pattern); if (match && match[1]) { return match[1]; } } return `table-${Date.now()}`; } private extractResourceName(input: string, resourceTypeEn: string): string { const patterns = [ new RegExp(`${resourceTypeEn}\\s+(?:named|called)?\\s*["]?([a-z0-9-_]+)["]?`, 'i'), /(?:named|called)\s+["]?([a-z0-9-_]+)["]?/i, /name\s+["]?([a-z0-9-_]+)["]?/i, ]; for (const pattern of patterns) { const match = input.match(pattern); if (match && match[1]) { return match[1]; } } return `resource-${Date.now()}`; } private extractInstanceType(input: string): string | null { for (const type of this.instanceTypes) { if (input.includes(type)) { return type; } } if (/\b(small|micro)\b/i.test(input)) return 't2.micro'; if (/\b(medium)\b/i.test(input)) return 't2.medium'; if (/\b(large)\b/i.test(input)) return 't2.large'; return null; } private extractEnvironment(input: string): string { if (/\b(prod|production)\b/i.test(input)) return 'production'; if (/\b(dev|development)\b/i.test(input)) return 'development'; if (/\b(test|testing)\b/i.test(input)) return 'testing'; if (/\b(staging)\b/i.test(input)) return 'staging'; return 'development'; } private extractPartitionKey(input: string): string | null { const patterns = [ /partition\s*key\s*["]?([a-z0-9_]+)["]?/i, /key\s*["]?([a-z0-9_]+)["]?/i, ]; for (const pattern of patterns) { const match = input.match(pattern); if (match && match[1]) { return match[1]; } } return null; } private extractRuntime(input: string): string | null { const runtimes = [ 'nodejs18.x', 'nodejs16.x', 'nodejs14.x', 'python3.11', 'python3.10', 'python3.9', 'java17', 'java11', 'dotnet6', 'dotnet7', 'go1.x', 'ruby3.2' ]; for (const runtime of runtimes) { if (input.includes(runtime)) { return runtime; } } if (/\b(node|nodejs|javascript)\b/i.test(input)) return 'nodejs18.x'; if (/\b(python|py)\b/i.test(input)) return 'python3.11'; if (/\b(java)\b/i.test(input)) return 'java17'; if (/\b(dotnet|c#|csharp)\b/i.test(input)) return 'dotnet7'; if (/\b(go|golang)\b/i.test(input)) return 'go1.x'; if (/\b(ruby)\b/i.test(input)) return 'ruby3.2'; return null; } private extractService(input: string): string { if (/\b(lambda|function)\b/i.test(input)) return 'lambda.amazonaws.com'; if (/\b(ec2|instance)\b/i.test(input)) return 'ec2.amazonaws.com'; if (/\b(s3|bucket)\b/i.test(input)) return 's3.amazonaws.com'; return 'lambda.amazonaws.com'; } private extractResourceId(input: string): string | undefined { const pattern = /\b([a-z]+-\d{10,})\b/i; const match = input.match(pattern); return match ? match[1] : undefined; } toResourceQuery(parsedCommand: ParsedCommand): ResourceQuery | null { if (parsedCommand.intent === 'unknown' || !parsedCommand.resourceType) { return null; } if (parsedCommand.intent === 'create') { return { resourceType: parsedCommand.resourceType, action: 'create', parameters: parsedCommand.parameters || {} }; } if (parsedCommand.intent === 'delete' && parsedCommand.resourceId) { return { resourceType: parsedCommand.resourceType, action: 'delete', parameters: {}, resourceId: parsedCommand.resourceId }; } return null; } generateHelpResponse(input: string): string { const suggestions = []; for (const [type, pattern] of Object.entries(this.resourcePatterns)) { if (pattern.test(input)) { suggestions.push(`• To create ${type === 's3' ? 'an S3 bucket' : type === 'ec2' ? 'an EC2 instance' : type === 'dynamodb' ? 'a DynamoDB table' : type === 'lambda' ? 'a Lambda function' : 'an IAM role'}: "Create ${type === 's3' ? 'an S3 bucket named my-bucket' : type === 'ec2' ? 'an EC2 instance t2.micro' : type === 'dynamodb' ? 'a DynamoDB table for users' : type === 'lambda' ? 'a Lambda function' : 'an IAM role for Lambda'}"`); break; } } if (suggestions.length === 0) { suggestions.push( '• To create resources: "Create an S3 bucket named my-project"', '• To delete resources: "Delete the resource s3-1234567890"', '• To list resources: "Show all resources"' ); } return `I could not fully understand your command. Here are some examples you can use:\n\n${suggestions.join('\n')}`; } }

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/gesguerra-wzln/aws-mcp-infrastucture'

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