Skip to main content
Glama

SAP OData to MCP Server

by Raistlin82
ai-enhanced-tools.ts15.5 kB
/** * AI-Enhanced MCP Tools for SAP OData Integration (Fixed Version) * Tools that leverage AI capabilities for intelligent SAP data operations */ import { Tool } from '@modelcontextprotocol/sdk/types.js'; import { aiIntegration } from '../services/ai-integration.js'; import { aiQueryBuilder } from '../services/ai-query-builder.js'; import { EntityType } from '../types/sap-types.js'; import { NaturalQueryResult, QueryContext } from '../services/ai-query-builder.js'; import { Logger } from '../utils/logger.js'; const logger = new Logger('AIEnhancedTools'); /** * Natural Language Query Builder Tool */ export class NaturalQueryBuilderTool implements Tool { [key: string]: unknown; name = 'natural-query-builder'; description = 'Convert natural language requests into optimized SAP OData queries using AI intelligence. Works with any MCP client (Claude, GPT, etc.)'; inputSchema = { type: 'object' as const, properties: { naturalQuery: { type: 'string' as const, description: 'Natural language query (e.g., "Show me all pending invoices from this month with amounts over 1000 euros")', }, entityType: { type: 'string' as const, description: 'Target SAP entity type (e.g., "Invoice", "PurchaseOrder", "Customer")', }, serviceId: { type: 'string' as const, description: 'SAP service identifier', }, userContext: { type: 'object' as const, properties: { role: { type: 'string' as const }, businessContext: { type: 'string' as const }, preferredFields: { type: 'array' as const, items: { type: 'string' as const }, }, }, }, }, required: ['naturalQuery', 'entityType', 'serviceId'], }; async execute(params: any): Promise<any> { try { logger.debug('Processing natural language query', { query: params.naturalQuery, entityType: params.entityType, }); const mockEntityType = this.createMockEntityType(params.entityType); const result = await aiQueryBuilder.buildQueryFromNaturalLanguage( params.naturalQuery, mockEntityType, params.userContext ); const executionUrl = `${params.serviceId}/${result.optimizedQuery.url}`; const suggestions = [ `Try: "${this.generateSuggestion(params.naturalQuery, mockEntityType)}"`, 'Add time filters for better performance', 'Specify fields you need to optimize data transfer', ]; logger.info('Successfully generated natural query', { originalQuery: params.naturalQuery, optimizedUrl: result.optimizedQuery.url, confidence: result.optimizedQuery.confidence, }); return { success: true, result, executionUrl, suggestions, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; logger.error('Natural query builder failed', { error: errorMessage }); return { success: false, error: errorMessage, suggestions: [ 'Try using simpler language', 'Specify the entity type more clearly', 'Check if the service is available', ], }; } } createMockEntityType(entityTypeName: string): EntityType { const baseProperties = [ { name: 'ID', type: 'Edm.String', nullable: false }, { name: 'CreatedDate', type: 'Edm.DateTime', nullable: true }, { name: 'Status', type: 'Edm.String', nullable: true }, ]; let specificProperties: any[] = []; if (entityTypeName.toLowerCase().includes('invoice')) { specificProperties = [ { name: 'InvoiceNumber', type: 'Edm.String', nullable: false }, { name: 'Amount', type: 'Edm.Double', nullable: false }, { name: 'DueDate', type: 'Edm.DateTime', nullable: true }, { name: 'CustomerName', type: 'Edm.String', nullable: true }, { name: 'Currency', type: 'Edm.String', nullable: true }, ]; } else if (entityTypeName.toLowerCase().includes('customer')) { specificProperties = [ { name: 'CustomerNumber', type: 'Edm.String', nullable: false }, { name: 'Name', type: 'Edm.String', nullable: false }, { name: 'Email', type: 'Edm.String', nullable: true }, { name: 'Address', type: 'Edm.String', nullable: true }, { name: 'Country', type: 'Edm.String', nullable: true }, ]; } else { specificProperties = [ { name: 'Name', type: 'Edm.String', nullable: true }, { name: 'Description', type: 'Edm.String', nullable: true }, { name: 'Value', type: 'Edm.Double', nullable: true }, ]; } return { name: entityTypeName, namespace: 'SAP', entitySet: `${entityTypeName}Set`, keys: specificProperties.length > 0 ? [specificProperties[0].name] : ['ID'], properties: [...baseProperties, ...specificProperties], navigationProperties: [], // Add missing properties for EntityType compatibility creatable: true, updatable: true, deletable: true, addressable: true, }; } private generateSuggestion(originalQuery: string, entityType: EntityType): string { const suggestions = [ `Show me recent ${entityType.name.toLowerCase()}s from this week`, `Find ${entityType.name.toLowerCase()}s with high values`, `List all pending ${entityType.name.toLowerCase()}s sorted by date`, `Get ${entityType.name.toLowerCase()}s created today`, ]; return suggestions[Math.floor(Math.random() * suggestions.length)]; } } /** * Smart Data Analysis Tool */ export class SmartDataAnalysisTool implements Tool { [key: string]: unknown; name = 'smart-data-analysis'; description = 'Analyze SAP data using AI to generate insights, trends, and business recommendations. Compatible with all MCP clients.'; inputSchema = { type: 'object' as const, properties: { data: { type: 'array' as const, description: 'Array of data records to analyze - each record is a key-value object', items: { type: 'object' as const, description: 'Data record with flexible schema for SAP entity analysis', additionalProperties: true, }, }, analysisType: { type: 'string' as const, enum: ['trend', 'anomaly', 'forecast', 'correlation'] as const, description: 'Type of analysis to perform', }, businessContext: { type: 'string' as const, description: 'Business context for the analysis', }, entityType: { type: 'string' as const, description: 'Type of SAP entity being analyzed', }, }, required: ['data', 'analysisType', 'entityType'], }; async execute(params: any): Promise<any> { try { logger.info('Starting smart data analysis', { recordCount: params.data.length, analysisType: params.analysisType, entityType: params.entityType, }); const prompt = `Analyze this ${params.entityType} data for ${params.analysisType} patterns and business insights`; const analysis = await aiIntegration.analyzeData(prompt, params.data, params.analysisType); const insights = analysis.insights.map( (insight: any) => `${insight.title}: ${insight.description} (${insight.impact} impact)` ); const recommendations = analysis.recommendations.map( (rec: any) => `${rec.title}: ${rec.description} (Priority: ${rec.priority})` ); return { success: true, analysis, insights, recommendations, confidence: analysis.confidence, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; logger.error('Smart data analysis failed', { error: errorMessage }); return { success: false, error: errorMessage, }; } } } /** * Query Performance Optimizer Tool */ export class QueryPerformanceOptimizerTool implements Tool { [key: string]: unknown; name = 'query-performance-optimizer'; description = 'Analyze and optimize SAP OData queries for better performance using AI recommendations.'; inputSchema = { type: 'object' as const, properties: { query: { type: 'string' as const, description: 'Original OData query URL to optimize', }, entityType: { type: 'string' as const, description: 'Target entity type', }, executionStats: { type: 'object' as const, properties: { executionTime: { type: 'number' as const }, recordCount: { type: 'number' as const }, dataSize: { type: 'number' as const }, }, }, optimizationGoals: { type: 'array' as const, items: { type: 'string' as const, enum: ['speed', 'bandwidth', 'accuracy', 'caching'] as const, }, description: 'Primary optimization objectives', }, }, required: ['query', 'entityType'], }; async execute(params: any): Promise<any> { try { logger.info('Optimizing query performance', { originalQuery: params.query, entityType: params.entityType, goals: params.optimizationGoals, }); // Create mock entity for optimization const tool = new NaturalQueryBuilderTool(); const mockEntityType = tool.createMockEntityType(params.entityType); const optimizationResult = await aiIntegration.optimizeQuery( `Optimize this query for performance: ${params.query}`, mockEntityType, { optimizationGoals: params.optimizationGoals } ); const improvements = this.analyzeImprovements(params.query, optimizationResult.url); const performanceGain = this.estimatePerformanceGain(improvements); return { success: true, originalQuery: params.query, optimizedQuery: optimizationResult.url, improvements, performanceGain, explanation: optimizationResult.explanation, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; logger.error('Query optimization failed', { error: errorMessage }); return { success: false, originalQuery: params.query, error: errorMessage, }; } } private analyzeImprovements(original: string, optimized: string): string[] { const improvements: string[] = []; if (optimized.includes('$select') && !original.includes('$select')) { improvements.push('Added field selection to reduce data transfer'); } if (optimized.includes('$top') && !original.includes('$top')) { improvements.push('Added result limit to improve response time'); } if (improvements.length === 0) { improvements.push('Query structure optimized for better SAP backend processing'); } return improvements; } private estimatePerformanceGain(improvements: string[]): string { const totalGain = Math.min(improvements.length * 15, 80); return `Estimated ${totalGain}% performance improvement`; } } /** * Business Process Insights Tool */ export class BusinessProcessInsightsTool implements Tool { [key: string]: unknown; name = 'business-process-insights'; description = 'Analyze SAP business processes to identify bottlenecks, inefficiencies, and optimization opportunities using AI.'; inputSchema = { type: 'object' as const, properties: { processType: { type: 'string' as const, enum: ['procurement', 'sales', 'finance', 'inventory', 'hr', 'general'] as const, description: 'Type of business process to analyze', }, processData: { type: 'array' as const, items: { type: 'object' as const }, description: 'Historical process execution data', }, timeframe: { type: 'string' as const, description: 'Analysis timeframe (e.g., "last 30 days", "Q3 2024")', }, focusAreas: { type: 'array' as const, items: { type: 'string' as const, enum: ['efficiency', 'costs', 'compliance', 'quality', 'speed'] as const, }, description: 'Specific areas to focus the analysis on', }, }, required: ['processType', 'processData'], }; async execute(params: any): Promise<any> { try { logger.info('Analyzing business process', { processType: params.processType, dataPoints: params.processData.length, timeframe: params.timeframe, }); const prompt = this.buildProcessAnalysisPrompt(params); const insights = await aiIntegration.generateBusinessInsights( params.processData, `${params.processType}Process`, prompt ); const processAnalysis = { summary: `Analysis of ${params.processType} process over ${params.timeframe || 'specified period'}`, keyMetrics: this.extractKeyMetrics(params.processData, params.processType), bottlenecks: insights .filter((i: any) => i.type === 'risk') .map((i: any) => i.title) .slice(0, 5), optimizationOpportunities: insights .filter((i: any) => i.type === 'trend') .map((i: any) => `Optimize ${i.title}`) .slice(0, 5), riskAreas: insights .filter((i: any) => i.type === 'risk') .map((i: any) => i.description) .slice(0, 3), }; const recommendations = insights.map((insight: any) => ({ title: insight.title, description: insight.description, priority: insight.impact, estimatedImpact: `${insight.impact} business impact`, implementationEffort: 'Medium effort required', })); return { success: true, processAnalysis, recommendations, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; logger.error('Business process analysis failed', { error: errorMessage }); return { success: false, error: errorMessage, }; } } private buildProcessAnalysisPrompt(params: any): string { return `Analyze ${params.processType} business process data for insights: Data points: ${params.processData.length} Timeframe: ${params.timeframe || 'Not specified'} Focus areas: ${params.focusAreas?.join(', ') || 'General analysis'} Identify bottlenecks, inefficiencies, and optimization opportunities.`; } private extractKeyMetrics(data: any[], processType: string): Record<string, any> { return { totalRecords: data.length, averageProcessingTime: 0, completionRate: 0, }; } } // Export all tools export const aiEnhancedTools = [ new NaturalQueryBuilderTool(), new SmartDataAnalysisTool(), new QueryPerformanceOptimizerTool(), new BusinessProcessInsightsTool(), ]; // Tool registry helpers export function getAIToolByName(name: string): Tool | undefined { return aiEnhancedTools.find(tool => tool.name === name); } export function getAllAIToolNames(): string[] { return aiEnhancedTools.map(tool => tool.name); } export function getAIToolsCount(): number { return aiEnhancedTools.length; }

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/Raistlin82/btp-sap-odata-to-mcp-server-optimized'

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