Skip to main content
Glama

DB & Calculator MCP Server

by dinek-k
server.js25.5 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import Database from './database.js'; import Calculator from './calculator.js'; class MCPServer { constructor() { this.server = new Server( { name: 'mcp-example-server', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, } ); this.database = new Database(); this.calculator = new Calculator(); this.setupTools(); this.setupResources(); this.setupPrompts(); } setupTools() { // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'query_database': return await this.handleDatabaseQuery(args); case 'get_all_users': return await this.handleGetAllUsers(args); case 'get_user_by_id': return await this.handleGetUserById(args); case 'add_user': return await this.handleAddUser(args); case 'update_user': return await this.handleUpdateUser(args); case 'delete_user': return await this.handleDeleteUser(args); case 'calculate': return await this.handleCalculate(args); case 'calculate_expression': return await this.handleCalculateExpression(args); case 'calculate_stats': return await this.handleCalculateStats(args); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { method: "tools/call", content: [ { type: 'text', text: `Error: ${error.message}`, }, ], }; } }); // Handle tool listing this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { method: "tools/list", tools: [ { name: 'query_database', description: 'Execute a custom SQL query on the database', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'SQL query to execute', }, }, required: ['query'], }, }, { name: 'get_all_users', description: 'Retrieve all users from the database', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number of users to return (optional)', }, }, }, }, { name: 'get_user_by_id', description: 'Retrieve a specific user by ID', inputSchema: { type: 'object', properties: { id: { type: 'number', description: 'User ID to retrieve', }, }, required: ['id'], }, }, { name: 'add_user', description: 'Add a new user to the database', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'User name', }, email: { type: 'string', description: 'User email', }, age: { type: 'number', description: 'User age', }, }, required: ['name', 'email'], }, }, { name: 'update_user', description: 'Update an existing user', inputSchema: { type: 'object', properties: { id: { type: 'number', description: 'User ID to update', }, name: { type: 'string', description: 'New user name', }, email: { type: 'string', description: 'New user email', }, age: { type: 'number', description: 'New user age', }, }, required: ['id'], }, }, { name: 'delete_user', description: 'Delete a user from the database', inputSchema: { type: 'object', properties: { id: { type: 'number', description: 'User ID to delete', }, }, required: ['id'], }, }, { name: 'calculate', description: 'Perform mathematical calculations', inputSchema: { type: 'object', properties: { operation: { type: 'string', description: 'Mathematical operation (add, subtract, multiply, divide, power, sqrt, sin, cos, tan, log, abs, round, floor, ceil)', enum: ['add', 'subtract', 'multiply', 'divide', 'power', 'sqrt', 'sin', 'cos', 'tan', 'log', 'abs', 'round', 'floor', 'ceil'], }, numbers: { type: 'array', items: { type: 'number' }, description: 'Numbers to perform the operation on', }, }, required: ['operation', 'numbers'], }, }, { name: 'calculate_expression', description: 'Evaluate a mathematical expression', inputSchema: { type: 'object', properties: { expression: { type: 'string', description: 'Mathematical expression to evaluate (e.g., "2 + 3 * 4")', }, }, required: ['expression'], }, }, { name: 'calculate_stats', description: 'Calculate statistical measures for a set of numbers', inputSchema: { type: 'object', properties: { numbers: { type: 'array', items: { type: 'number' }, description: 'Array of numbers to calculate statistics for', }, }, required: ['numbers'], }, }, ], }; }); } setupResources() { // Handle resource listing this.server.setRequestHandler(ListResourcesRequestSchema, async () => { return { method: "resources/list", resources: [ { uri: "mcp://database/users.json", name: "Users Database Export", description: "All users from the database in JSON format", mimeType: "application/json" }, { uri: "mcp://database/users.csv", name: "Users CSV Export", description: "All users from the database in CSV format", mimeType: "text/csv" }, { uri: "mcp://database/stats.json", name: "Database Statistics", description: "Database statistics and metrics", mimeType: "application/json" }, { uri: "mcp://calculator/operations.json", name: "Calculator Operations", description: "Available calculator operations and their descriptions", mimeType: "application/json" }, { uri: "mcp://system/info.json", name: "System Information", description: "Server system information and status", mimeType: "application/json" } ], }; }); // Handle resource reading this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const { uri } = request.params; try { switch (uri) { case "mcp://database/users.json": return await this.handleUsersJsonResource(); case "mcp://database/users.csv": return await this.handleUsersCsvResource(); case "mcp://database/stats.json": return await this.handleDatabaseStatsResource(); case "mcp://calculator/operations.json": return await this.handleCalculatorOperationsResource(); case "mcp://system/info.json": return await this.handleSystemInfoResource(); default: throw new Error(`Resource not found: ${uri}`); } } catch (error) { return { method: "resources/read", contents: [ { uri: uri, mimeType: "text/plain", text: `Error reading resource: ${error.message}`, }, ], }; } }); } setupPrompts() { // Handle prompt listing this.server.setRequestHandler(ListPromptsRequestSchema, async () => { return { method: "prompts/list", prompts: [ { name: "user-analysis", description: "Analyze user data and provide insights", arguments: { type: "object", properties: { analysisType: { type: "string", enum: ["demographics", "activity", "trends"], description: "Type of analysis to perform" }, includeStats: { type: "boolean", description: "Include statistical calculations" } }, required: ["analysisType"] } }, { name: "database-report", description: "Generate a comprehensive database report", arguments: { type: "object", properties: { reportType: { type: "string", enum: ["summary", "detailed", "export"], description: "Type of report to generate" }, format: { type: "string", enum: ["json", "csv", "markdown"], description: "Output format for the report" } }, required: ["reportType"] } }, { name: "calculator-tutorial", description: "Generate a tutorial for calculator operations", arguments: { type: "object", properties: { operation: { type: "string", enum: ["basic", "advanced", "trigonometric", "utility"], description: "Category of operations to cover" }, includeExamples: { type: "boolean", description: "Include practical examples" } }, required: ["operation"] } } ], }; }); // Handle prompt retrieval this.server.setRequestHandler(GetPromptRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case "user-analysis": return await this.handleUserAnalysisPrompt(args); case "database-report": return await this.handleDatabaseReportPrompt(args); case "calculator-tutorial": return await this.handleCalculatorTutorialPrompt(args); default: throw new Error(`Prompt not found: ${name}`); } } catch (error) { return { method: "prompts/get", prompt: { name: name, description: `Error generating prompt: ${error.message}`, arguments: {}, messages: [ { role: "system", content: `Error: ${error.message}` } ] }, }; } }); } // Resource handlers async handleUsersJsonResource() { const users = await this.database.all('SELECT * FROM users'); return { method: "resources/read", contents: [ { uri: "mcp://database/users.json", mimeType: "application/json", text: JSON.stringify(users, null, 2), }, ], }; } async handleUsersCsvResource() { const users = await this.database.all('SELECT * FROM users'); // Convert to CSV const headers = ['id', 'name', 'email', 'age', 'created_at']; const csvRows = [headers.join(',')]; users.forEach(user => { const row = headers.map(header => { const value = user[header]; return typeof value === 'string' ? `"${value}"` : value; }); csvRows.push(row.join(',')); }); return { method: "resources/read", contents: [ { uri: "mcp://database/users.csv", mimeType: "text/csv", text: csvRows.join('\n'), }, ], }; } async handleDatabaseStatsResource() { const totalUsers = await this.database.get('SELECT COUNT(*) as count FROM users'); const avgAge = await this.database.get('SELECT AVG(age) as avg_age FROM users WHERE age IS NOT NULL'); const ageStats = await this.database.get('SELECT MIN(age) as min_age, MAX(age) as max_age FROM users WHERE age IS NOT NULL'); const stats = { totalUsers: totalUsers.count, averageAge: avgAge.avg_age ? Math.round(avgAge.avg_age * 100) / 100 : null, ageRange: { min: ageStats.min_age, max: ageStats.max_age }, databaseInfo: { type: "SQLite", location: this.database.dbPath, lastUpdated: new Date().toISOString() } }; return { method: "resources/read", contents: [ { uri: "mcp://database/stats.json", mimeType: "application/json", text: JSON.stringify(stats, null, 2), }, ], }; } async handleCalculatorOperationsResource() { const operations = this.calculator.getAvailableOperations(); const operationDetails = operations.map(op => ({ name: op, description: this.getOperationDescription(op), examples: this.getOperationExamples(op) })); const calculatorInfo = { availableOperations: operationDetails, totalOperations: operations.length, categories: { basic: ['add', 'subtract', 'multiply', 'divide'], advanced: ['power', 'sqrt', 'log'], trigonometric: ['sin', 'cos', 'tan'], utility: ['abs', 'round', 'floor', 'ceil'] } }; return { method: "resources/read", contents: [ { uri: "mcp://calculator/operations.json", mimeType: "application/json", text: JSON.stringify(calculatorInfo, null, 2), }, ], }; } async handleSystemInfoResource() { const systemInfo = { server: { name: 'mcp-example-server', version: '1.0.0', uptime: process.uptime(), startTime: new Date(Date.now() - process.uptime() * 1000).toISOString() }, capabilities: { tools: true, resources: true, prompts: true }, tools: { database: 6, calculator: 3, total: 9 }, resources: { database: 3, calculator: 1, system: 1, total: 5 }, prompts: { analysis: 2, reporting: 1, total: 3 }, timestamp: new Date().toISOString() }; return { method: "resources/read", contents: [ { uri: "mcp://system/info.json", mimeType: "application/json", text: JSON.stringify(systemInfo, null, 2), }, ], }; } getOperationDescription(operation) { const descriptions = { add: "Add two or more numbers", subtract: "Subtract numbers", multiply: "Multiply numbers", divide: "Divide numbers (with zero check)", power: "Raise a number to a power", sqrt: "Calculate square root", sin: "Calculate sine (in radians)", cos: "Calculate cosine (in radians)", tan: "Calculate tangent (in radians)", log: "Calculate natural logarithm", abs: "Calculate absolute value", round: "Round to nearest integer", floor: "Round down to integer", ceil: "Round up to integer" }; return descriptions[operation] || "Mathematical operation"; } getOperationExamples(operation) { const examples = { add: ["add(5, 3) = 8", "add(1, 2, 3, 4) = 10"], subtract: ["subtract(10, 3) = 7"], multiply: ["multiply(4, 5) = 20"], divide: ["divide(10, 2) = 5"], power: ["power(2, 3) = 8"], sqrt: ["sqrt(16) = 4"], sin: ["sin(0) = 0", "sin(Math.PI/2) = 1"], cos: ["cos(0) = 1", "cos(Math.PI) = -1"], tan: ["tan(0) = 0"], log: ["log(Math.E) = 1"], abs: ["abs(-5) = 5"], round: ["round(3.7) = 4"], floor: ["floor(3.7) = 3"], ceil: ["ceil(3.2) = 4"] }; return examples[operation] || []; } // Database handlers async handleDatabaseQuery(args) { const { query } = args; const result = await this.database.all(query); return { method: "tools/call", content: [ { type: 'text', text: `Query executed successfully. Found ${result.length} rows:\n${JSON.stringify(result, null, 2)}`, }, ], }; } async handleGetAllUsers(args) { const { limit } = args; const query = limit ? 'SELECT * FROM users LIMIT ?' : 'SELECT * FROM users'; const params = limit ? [limit] : []; const users = await this.database.all(query, params); return { method: "tools/call", content: [ { type: 'text', text: `Retrieved ${users.length} users:\n${JSON.stringify(users, null, 2)}`, }, ], }; } async handleGetUserById(args) { const { id } = args; const user = await this.database.get('SELECT * FROM users WHERE id = ?', [id]); if (!user) { return { method: "tools/call", content: [ { type: 'text', text: `User with ID ${id} not found.`, }, ], }; } return { method: "tools/call", content: [ { type: 'text', text: `User found:\n${JSON.stringify(user, null, 2)}`, }, ], }; } async handleAddUser(args) { const { name, email, age } = args; const result = await this.database.run( 'INSERT INTO users (name, email, age) VALUES (?, ?, ?)', [name, email, age || null] ); return { method: "tools/call", content: [ { type: 'text', text: `User added successfully with ID: ${result.id}`, }, ], }; } async handleUpdateUser(args) { const { id, name, email, age } = args; const updates = []; const params = []; if (name !== undefined) { updates.push('name = ?'); params.push(name); } if (email !== undefined) { updates.push('email = ?'); params.push(email); } if (age !== undefined) { updates.push('age = ?'); params.push(age); } if (updates.length === 0) { return { method: "tools/call", content: [ { type: 'text', text: 'No fields to update provided.', }, ], }; } params.push(id); const result = await this.database.run( `UPDATE users SET ${updates.join(', ')} WHERE id = ?`, params ); return { method: "tools/call", content: [ { type: 'text', text: `User updated successfully. ${result.changes} row(s) affected.`, }, ], }; } async handleDeleteUser(args) { const { id } = args; const result = await this.database.run('DELETE FROM users WHERE id = ?', [id]); return { method: "tools/call", content: [ { type: 'text', text: `User deleted successfully. ${result.changes} row(s) affected.`, }, ], }; } // Calculator handlers async handleCalculate(args) { const { operation, numbers } = args; const result = this.calculator.calculate(operation, ...numbers); return { method: "tools/call", content: [ { type: 'text', text: `Calculation result: ${JSON.stringify(result, null, 2)}`, }, ], }; } async handleCalculateExpression(args) { const { expression } = args; const result = this.calculator.calculateExpression(expression); return { method: "tools/call", content: [ { type: 'text', text: `Expression result: ${JSON.stringify(result, null, 2)}`, }, ], }; } async handleCalculateStats(args) { const { numbers } = args; const result = this.calculator.calculateStats(numbers); return { method: "tools/call", content: [ { type: 'text', text: `Statistical analysis: ${JSON.stringify(result, null, 2)}`, }, ], }; } // Prompt handlers async handleUserAnalysisPrompt(args) { const { analysisType, includeStats = false } = args; let content = `You are a data analyst. Analyze the user database and provide insights about ${analysisType}.`; if (includeStats) { content += "\n\nInclude statistical analysis such as averages, distributions, and trends."; } const messages = [ { role: "system", content: content }, { role: "user", content: `Please analyze the user data focusing on ${analysisType}. ${includeStats ? 'Include detailed statistics.' : 'Provide a general overview.'}` } ]; return { method: "prompts/get", prompt: { name: "user-analysis", description: `Analyze user data for ${analysisType}${includeStats ? ' with statistics' : ''}`, arguments: args, messages: messages }, }; } async handleDatabaseReportPrompt(args) { const { reportType, format = "json" } = args; let content = `You are a database administrator. Generate a ${reportType} report of the database in ${format} format.`; if (reportType === "detailed") { content += "\n\nInclude detailed information about tables, relationships, and data quality."; } else if (reportType === "export") { content += "\n\nProvide export-ready data with proper formatting."; } const messages = [ { role: "system", content: content }, { role: "user", content: `Generate a ${reportType} database report in ${format} format.` } ]; return { method: "prompts/get", prompt: { name: "database-report", description: `Generate ${reportType} database report in ${format} format`, arguments: args, messages: messages }, }; } async handleCalculatorTutorialPrompt(args) { const { operation, includeExamples = true } = args; let content = `You are a mathematics tutor. Create a tutorial for ${operation} calculator operations.`; if (includeExamples) { content += "\n\nInclude practical examples and step-by-step explanations."; } const messages = [ { role: "system", content: content }, { role: "user", content: `Create a tutorial for ${operation} calculator operations. ${includeExamples ? 'Include examples.' : 'Focus on theory.'}` } ]; return { method: "prompts/get", prompt: { name: "calculator-tutorial", description: `Tutorial for ${operation} calculator operations${includeExamples ? ' with examples' : ''}`, arguments: args, messages: messages }, }; } async start() { try { // Initialize database await this.database.initialize(); // Start MCP server const transport = new StdioServerTransport(); await this.server.connect(transport); // Don't log to stdout as it interferes with JSON-RPC // console.log('MCP server started successfully'); } catch (error) { console.error('Failed to start MCP server:', error); process.exit(1); } } } // Start the server const server = new MCPServer(); server.start().catch(console.error);

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/dinek-k/MCP-Server-Example-1'

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