@medikode/mcp-server
Version:
Model Context Protocol (MCP) server for Medikode healthcare SaaS platform
210 lines (184 loc) • 6.88 kB
JavaScript
const backendClient = require('./backendClient');
const crypto = require('crypto');
/**
* MCP Usage Logger using Backend Service
* This replaces the SQLite implementation with calls to the backend-service
*/
class MCPUsageLogger {
constructor() {
this.backendClient = backendClient;
}
/**
* Initialize the usage logger (no-op for backend service)
*/
async initializeDatabase() {
console.log('MCP Usage Logger initialized with backend-service integration');
return Promise.resolve();
}
/**
* Log MCP usage to backend-service database
*/
async logUsage(logData) {
try {
const timestamp = new Date().toISOString();
const {
requestId,
apiKeyId,
toolName,
requestData,
responseData,
statusCode,
processingTimeMs,
errorMessage,
userAgent,
ipAddress
} = logData;
console.log(`[${timestamp}] Logging MCP usage for tool: ${toolName}, API key: ${apiKeyId}`);
// Calculate request hash
const requestString = JSON.stringify(requestData);
const requestHash = crypto.createHash('sha256').update(requestString).digest('hex');
// Prepare metadata
const metadata = {
tool_name: toolName,
call_id: requestId,
api_time_ms: processingTimeMs,
input_length: this.calculateInputLength(requestData),
output_length: this.calculateOutputLength(responseData),
status_code: statusCode,
error_message: errorMessage,
user_agent: userAgent,
ip_address: ipAddress,
input_type: 'MCP' // Distinguish MCP calls from regular API calls
};
// Store in backend-service
const result = await this.backendClient.storeMcpCall(
requestData,
responseData,
apiKeyId,
requestHash,
metadata,
false // not cached
);
console.log(`[${timestamp}] MCP usage logged successfully with ID: ${result.id}`);
return result.id;
} catch (error) {
console.error('Error logging MCP usage:', error);
// Don't throw error to avoid breaking the main flow
return null;
}
}
/**
* Check cache for MCP call
*/
async checkCache(requestData, requestHash, environment = 'sandbox') {
try {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] Checking MCP cache for hash: ${requestHash}`);
const cachedResult = await this.backendClient.checkMcpCache(
requestData,
requestHash,
environment
);
if (cachedResult) {
console.log(`[${timestamp}] Found cached MCP result from ${cachedResult.created_at}`);
return cachedResult;
} else {
console.log(`[${timestamp}] No cached MCP result found`);
return null;
}
} catch (error) {
console.error('Error checking MCP cache:', error);
return null; // Return null on error to allow processing to continue
}
}
/**
* Get usage statistics
*/
async getUsageStats(apiKeyId, startDate = null, endDate = null, environment = 'sandbox') {
try {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] Getting MCP usage stats for API key: ${apiKeyId}`);
const stats = await this.backendClient.getMcpStats(
apiKeyId,
startDate,
endDate,
environment
);
console.log(`[${timestamp}] Retrieved MCP usage stats`);
return stats;
} catch (error) {
console.error('Error getting MCP usage stats:', error);
throw error;
}
}
/**
* Get usage history
*/
async getUsageHistory(userId, limit = 100, offset = 0, environment = 'sandbox', inputType = null) {
try {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] Getting MCP usage history for user: ${userId}`);
const history = await this.backendClient.getMcpCallHistory(
userId,
limit,
offset,
environment,
inputType
);
console.log(`[${timestamp}] Retrieved MCP usage history`);
return history;
} catch (error) {
console.error('Error getting MCP usage history:', error);
throw error;
}
}
/**
* Calculate input length for metadata
*/
calculateInputLength(requestData) {
try {
if (typeof requestData === 'string') {
return requestData.length;
} else if (typeof requestData === 'object') {
return JSON.stringify(requestData).length;
}
return 0;
} catch (error) {
return 0;
}
}
/**
* Calculate output length for metadata
*/
calculateOutputLength(responseData) {
try {
if (typeof responseData === 'string') {
return responseData.length;
} else if (typeof responseData === 'object') {
return JSON.stringify(responseData).length;
}
return 0;
} catch (error) {
return 0;
}
}
/**
* Close database connection (no-op for backend service)
*/
closeDatabase() {
console.log('MCP Usage Logger closed (backend-service integration)');
}
}
// Create singleton instance
const usageLogger = new MCPUsageLogger();
module.exports = {
initializeDatabase: () => usageLogger.initializeDatabase(),
logUsage: (logData) => usageLogger.logUsage(logData),
checkCache: (requestData, requestHash, environment) =>
usageLogger.checkCache(requestData, requestHash, environment),
getUsageStats: (apiKeyId, startDate, endDate, environment) =>
usageLogger.getUsageStats(apiKeyId, startDate, endDate, environment),
getUsageHistory: (userId, limit, offset, environment) =>
usageLogger.getUsageHistory(userId, limit, offset, environment),
closeDatabase: () => usageLogger.closeDatabase()
};