3268 lines
92 KiB
JavaScript
3268 lines
92 KiB
JavaScript
/**
|
|
* @fileoverview Mock Factory for Laravel Healthcare MCP Server tests
|
|
* Provides a centralized factory for creating and managing all test mocks
|
|
*/
|
|
|
|
import { jest } from "@jest/globals";
|
|
import { httpMockManager } from "./httpMocks.js";
|
|
import { authMockManager } from "./authMocks.js";
|
|
import { healthcareDataMockManager } from "./healthcareDataMocks.js";
|
|
|
|
/**
|
|
* Comprehensive Mock Factory for all MCP server components
|
|
*/
|
|
export class MockFactory {
|
|
constructor() {
|
|
this.httpMocks = httpMockManager;
|
|
this.authMocks = authMockManager;
|
|
this.healthcareMocks = healthcareDataMockManager;
|
|
this.componentMocks = new Map();
|
|
}
|
|
|
|
/**
|
|
* Create a complete mock environment for MCP server testing
|
|
* @param {Object} options - Configuration options
|
|
* @returns {Object} Complete mock environment
|
|
*/
|
|
createMockEnvironment(options = {}) {
|
|
const {
|
|
authTypes = ["provider", "patient", "partner", "affiliate", "network"],
|
|
enableHttpMocks = true,
|
|
enableAuthMocks = true,
|
|
enableHealthcareMocks = true,
|
|
customMocks = {},
|
|
} = options;
|
|
|
|
const mockEnv = {
|
|
axios: null,
|
|
authManager: null,
|
|
apiClient: null,
|
|
toolGenerator: null,
|
|
mcpServer: null,
|
|
config: null,
|
|
};
|
|
|
|
// Setup HTTP mocks
|
|
if (enableHttpMocks) {
|
|
mockEnv.axios = this.httpMocks.createMockAxios();
|
|
this.httpMocks.mockHealthcareEndpoints();
|
|
|
|
// Mock authentication endpoints for all auth types
|
|
authTypes.forEach((authType) => {
|
|
this.httpMocks.mockAuthLogin(authType, true);
|
|
});
|
|
}
|
|
|
|
// Setup authentication mocks
|
|
if (enableAuthMocks) {
|
|
mockEnv.authManager = this.authMocks.createMockAuthManager();
|
|
this.authMocks.setupDefaultCredentials();
|
|
}
|
|
|
|
// Setup component mocks
|
|
mockEnv.config = this.createMockConfigManager();
|
|
mockEnv.apiClient = this.createMockApiClient(
|
|
mockEnv.axios,
|
|
mockEnv.authManager
|
|
);
|
|
mockEnv.toolGenerator = this.createMockToolGenerator(mockEnv.apiClient);
|
|
mockEnv.mcpServer = this.createMockMcpServer();
|
|
|
|
// Apply custom mocks
|
|
Object.entries(customMocks).forEach(([key, mockValue]) => {
|
|
mockEnv[key] = mockValue;
|
|
});
|
|
|
|
return mockEnv;
|
|
}
|
|
|
|
/**
|
|
* Create mock ConfigManager
|
|
* @returns {Object} Mock ConfigManager instance
|
|
*/
|
|
createMockConfigManager() {
|
|
const mockConfig = {
|
|
get: jest.fn(),
|
|
getAll: jest.fn(),
|
|
getSummary: jest.fn(),
|
|
isValid: jest.fn(),
|
|
set: jest.fn(),
|
|
load: jest.fn(),
|
|
};
|
|
|
|
// Setup default implementations
|
|
mockConfig.get.mockImplementation((key) => {
|
|
const defaults = {
|
|
LARAVEL_API_BASE_URL: "https://test-api.example.com",
|
|
LARAVEL_API_TIMEOUT: "5000",
|
|
LARAVEL_API_RETRY_ATTEMPTS: "2",
|
|
NODE_ENV: "test",
|
|
};
|
|
return defaults[key] || process.env[key];
|
|
});
|
|
|
|
mockConfig.getAll.mockImplementation((includeSecrets = false) => ({
|
|
LARAVEL_API_BASE_URL: "https://test-api.example.com",
|
|
LARAVEL_API_TIMEOUT: 5000,
|
|
LARAVEL_API_RETRY_ATTEMPTS: 2,
|
|
TOKEN_CACHE_DURATION: 300,
|
|
NODE_ENV: "test",
|
|
}));
|
|
|
|
mockConfig.getSummary.mockReturnValue({
|
|
baseUrl: "https://test-api.example.com",
|
|
timeout: 5000,
|
|
environment: "test",
|
|
});
|
|
|
|
mockConfig.isValid.mockReturnValue(true);
|
|
|
|
return mockConfig;
|
|
}
|
|
|
|
/**
|
|
* Create mock ApiClient
|
|
* @param {Object} mockAxios - Mock axios instance
|
|
* @param {Object} mockAuthManager - Mock auth manager
|
|
* @returns {Object} Mock ApiClient instance
|
|
*/
|
|
createMockApiClient(mockAxios, mockAuthManager) {
|
|
const mockApiClient = {
|
|
request: jest.fn(),
|
|
get: jest.fn(),
|
|
post: jest.fn(),
|
|
put: jest.fn(),
|
|
patch: jest.fn(),
|
|
delete: jest.fn(),
|
|
getHealthStatus: jest.fn(),
|
|
setAuthToken: jest.fn(),
|
|
clearAuthToken: jest.fn(),
|
|
};
|
|
|
|
// Setup method implementations
|
|
mockApiClient.request.mockImplementation(async (config) => {
|
|
if (mockAxios) {
|
|
return mockAxios.request(config);
|
|
}
|
|
return { status: 200, data: { success: true } };
|
|
});
|
|
|
|
["get", "post", "put", "patch", "delete"].forEach((method) => {
|
|
mockApiClient[method].mockImplementation(async (...args) => {
|
|
if (mockAxios && mockAxios[method]) {
|
|
return mockAxios[method](...args);
|
|
}
|
|
return { status: 200, data: { success: true } };
|
|
});
|
|
});
|
|
|
|
mockApiClient.getHealthStatus.mockReturnValue({
|
|
status: "healthy",
|
|
baseURL: "https://test-api.example.com",
|
|
timeout: 5000,
|
|
lastCheck: new Date().toISOString(),
|
|
});
|
|
|
|
return mockApiClient;
|
|
}
|
|
|
|
/**
|
|
* Create mock ToolGenerator
|
|
* @param {Object} mockApiClient - Mock API client
|
|
* @returns {Object} Mock ToolGenerator instance
|
|
*/
|
|
createMockToolGenerator(mockApiClient) {
|
|
const mockToolGenerator = {
|
|
generateAllTools: jest.fn(),
|
|
getTool: jest.fn(),
|
|
getToolsByAuthType: jest.fn(),
|
|
validateTool: jest.fn(),
|
|
executeTool: jest.fn(),
|
|
};
|
|
|
|
// Setup method implementations
|
|
mockToolGenerator.generateAllTools.mockReturnValue(
|
|
this.generateMockToolsList()
|
|
);
|
|
|
|
mockToolGenerator.getTool.mockImplementation((toolName) => {
|
|
const tools = mockToolGenerator.generateAllTools();
|
|
return tools.find((tool) => tool.name === toolName) || null;
|
|
});
|
|
|
|
mockToolGenerator.getToolsByAuthType.mockImplementation((authType) => {
|
|
const tools = mockToolGenerator.generateAllTools();
|
|
return tools.filter((tool) => tool.name.startsWith(authType));
|
|
});
|
|
|
|
mockToolGenerator.validateTool.mockReturnValue({ valid: true, errors: [] });
|
|
|
|
mockToolGenerator.executeTool.mockImplementation(
|
|
async (toolName, parameters) => {
|
|
// Simulate network delay
|
|
await new Promise((resolve) => setTimeout(resolve, Math.random() * 50));
|
|
|
|
// Check for specific HTTP mocks first (for all tools, not just medicine import)
|
|
if (
|
|
this.httpMocks &&
|
|
this.httpMocks.mocks &&
|
|
this.httpMocks.mocks.size > 0
|
|
) {
|
|
// Check all HTTP mocks for error status codes first
|
|
for (const [key, mock] of this.httpMocks.mocks) {
|
|
// Check if mock should fail or has error response
|
|
if (mock.shouldFail && mock.error && mock.error.response) {
|
|
// Handle error stored in mock.error.response
|
|
if (mock.error.response.status >= 400) {
|
|
const errorMessage =
|
|
mock.error.response.data?.error ||
|
|
mock.error.response.data?.message ||
|
|
`HTTP ${mock.error.response.status} Error`;
|
|
throw new Error(errorMessage);
|
|
}
|
|
} else if (mock.response && mock.response.status >= 400) {
|
|
// Handle error stored in mock.response
|
|
const errorMessage =
|
|
mock.response.data?.error ||
|
|
mock.response.data?.message ||
|
|
`HTTP ${mock.response.status} Error`;
|
|
throw new Error(errorMessage);
|
|
}
|
|
}
|
|
|
|
// Then check for specific HTTP mock data to return
|
|
for (const [key, mock] of this.httpMocks.mocks) {
|
|
if (mock.response && mock.response.data) {
|
|
// For medicine import tools, only return HTTP mock data if no file format errors
|
|
if (toolName.includes("emrimportMedicine")) {
|
|
// Check for file format validation errors first (not content validation errors)
|
|
if (this.shouldSimulateFileFormatError(toolName, parameters)) {
|
|
// Let it fall through to the specific response generator which will handle the error
|
|
break;
|
|
}
|
|
// Only return HTTP mock data if it's specifically for medicine import
|
|
if (key.includes("import") || key.includes("medicine")) {
|
|
// Wrap the HTTP mock data in the expected structure
|
|
return {
|
|
success: mock.response.data.success,
|
|
data: mock.response.data,
|
|
};
|
|
}
|
|
}
|
|
|
|
// For public tools with HTTP mocks (like patientavailableSlot)
|
|
if (
|
|
toolName.includes("patientavailableSlot") ||
|
|
toolName.includes("patientBookAppointment")
|
|
) {
|
|
// Check if the HTTP mock key matches the expected pattern
|
|
if (
|
|
key.includes("available-slots") ||
|
|
key.includes("book-appointment")
|
|
) {
|
|
// Wrap the HTTP mock data in the expected structure
|
|
return {
|
|
success:
|
|
mock.response.data.success !== undefined
|
|
? mock.response.data.success
|
|
: true,
|
|
data: mock.response.data,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// For medicine import tools, use specific response generator
|
|
if (toolName.includes("emrimportMedicine")) {
|
|
return this.generateMedicineImportResponse(toolName, parameters);
|
|
}
|
|
|
|
// Return healthcare-specific mock responses
|
|
return this.generateHealthcareResponse(toolName, parameters);
|
|
}
|
|
);
|
|
|
|
return mockToolGenerator;
|
|
}
|
|
|
|
/**
|
|
* Create mock McpServer
|
|
* @returns {Object} Mock McpServer instance
|
|
*/
|
|
createMockMcpServer() {
|
|
const mockMcpServer = {
|
|
start: jest.fn(),
|
|
stop: jest.fn(),
|
|
handleRequest: jest.fn(),
|
|
listTools: jest.fn(),
|
|
callTool: jest.fn(),
|
|
getServerInfo: jest.fn(),
|
|
};
|
|
|
|
// Setup method implementations
|
|
mockMcpServer.start.mockResolvedValue({ success: true, port: 3000 });
|
|
mockMcpServer.stop.mockResolvedValue({ success: true });
|
|
|
|
mockMcpServer.listTools.mockReturnValue([
|
|
{ name: "public_create_login", description: "Public: General login" },
|
|
{
|
|
name: "provider_get_patients",
|
|
description: "Provider: Get patient list",
|
|
},
|
|
]);
|
|
|
|
mockMcpServer.callTool.mockImplementation(async (name, arguments_) => {
|
|
return {
|
|
content: [
|
|
{
|
|
type: "text",
|
|
text: `Mock response for tool ${name} with arguments: ${JSON.stringify(
|
|
arguments_
|
|
)}`,
|
|
},
|
|
],
|
|
};
|
|
});
|
|
|
|
mockMcpServer.getServerInfo.mockReturnValue({
|
|
name: "Laravel Healthcare MCP Server",
|
|
version: "1.0.0",
|
|
description: "Mock MCP Server for testing",
|
|
});
|
|
|
|
return mockMcpServer;
|
|
}
|
|
|
|
/**
|
|
* Create mock for specific MCP tool
|
|
* @param {string} toolName - Name of the tool
|
|
* @param {Object} mockResponse - Mock response data
|
|
* @param {boolean} shouldFail - Whether the tool should fail
|
|
* @returns {Function} Mock tool function
|
|
*/
|
|
createMockTool(toolName, mockResponse = {}, shouldFail = false) {
|
|
return jest.fn().mockImplementation(async (parameters) => {
|
|
if (shouldFail) {
|
|
throw new Error(`Mock error for tool ${toolName}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: mockResponse,
|
|
toolName,
|
|
parameters,
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Setup mocks for specific authentication type
|
|
* @param {string} authType - Authentication type
|
|
* @param {Object} options - Setup options
|
|
*/
|
|
setupAuthTypeMocks(authType, options = {}) {
|
|
const {
|
|
shouldAuthSucceed = true,
|
|
customCredentials = null,
|
|
customEndpoints = [],
|
|
} = options;
|
|
|
|
// Setup authentication
|
|
if (customCredentials) {
|
|
this.authMocks.setMockCredentials(authType, customCredentials);
|
|
}
|
|
|
|
// Setup HTTP endpoints
|
|
this.httpMocks.mockAuthLogin(authType, shouldAuthSucceed);
|
|
|
|
// Setup custom endpoints
|
|
customEndpoints.forEach((endpoint) => {
|
|
this.httpMocks.mockRequest(
|
|
endpoint.method,
|
|
endpoint.url,
|
|
endpoint.response,
|
|
endpoint.shouldFail || false,
|
|
endpoint.error || null
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generate healthcare-specific mock responses
|
|
* @param {string} toolName - Name of the tool
|
|
* @param {Object} parameters - Tool parameters
|
|
* @returns {Object} Healthcare-specific mock response
|
|
*/
|
|
generateHealthcareResponse(toolName, parameters) {
|
|
// Check for error scenarios first
|
|
const errorResponse = this.checkForErrorScenarios(toolName, parameters);
|
|
if (errorResponse) {
|
|
throw errorResponse;
|
|
}
|
|
|
|
// Clinical workflows responses
|
|
if (toolName.includes("prescription")) {
|
|
return this.generatePrescriptionResponse(toolName, parameters);
|
|
}
|
|
|
|
if (toolName.includes("emrimportMedicine")) {
|
|
return this.generateMedicineImportResponse(toolName, parameters);
|
|
}
|
|
|
|
// Patient data management responses
|
|
if (toolName.startsWith("patient_")) {
|
|
return this.generatePatientDataResponse(toolName, parameters);
|
|
}
|
|
|
|
// Provider EMR management responses
|
|
if (
|
|
toolName.includes("medicalRecordscreate") ||
|
|
toolName.includes("getPatientInfo") ||
|
|
toolName.includes("updatePatientInfo")
|
|
) {
|
|
return this.generateProviderEMRResponse(toolName, parameters);
|
|
}
|
|
|
|
// HIPAA compliance specific responses
|
|
if (
|
|
toolName.includes("hipaa") ||
|
|
toolName.includes("audit") ||
|
|
toolName.includes("breach") ||
|
|
toolName.includes("baa") ||
|
|
toolName.includes("security_incident") ||
|
|
toolName.includes("thirdPartyService")
|
|
) {
|
|
return this.generateHIPAAComplianceResponse(toolName, parameters);
|
|
}
|
|
|
|
// Public data access tools
|
|
if (toolName.includes("checkEmail") || toolName.includes("checkUser")) {
|
|
return this.generatePublicDataAccessResponse(toolName, parameters);
|
|
}
|
|
|
|
// Appointment and booking tools
|
|
if (
|
|
toolName.includes("availableSlot") ||
|
|
toolName.includes("BookAppointment")
|
|
) {
|
|
return this.generateAppointmentResponse(toolName, parameters);
|
|
}
|
|
|
|
// Email verification tools
|
|
if (
|
|
toolName.includes("verifyEmail") ||
|
|
toolName.includes("resendVerification")
|
|
) {
|
|
return this.generateEmailVerificationResponse(toolName, parameters);
|
|
}
|
|
|
|
// Medical coding and documentation
|
|
if (
|
|
toolName.includes("icd10") ||
|
|
toolName.includes("cpt") ||
|
|
toolName.includes("coding")
|
|
) {
|
|
return this.generateMedicalCodingResponse(toolName, parameters);
|
|
}
|
|
|
|
if (toolName.includes("clinicalHandoff")) {
|
|
return this.generateHandoffResponse(toolName, parameters);
|
|
}
|
|
|
|
if (toolName.includes("careTeam")) {
|
|
return this.generateCareTeamResponse(toolName, parameters);
|
|
}
|
|
|
|
if (toolName.includes("qualityMeasures")) {
|
|
return this.generateQualityMeasuresResponse(toolName, parameters);
|
|
}
|
|
|
|
if (toolName.includes("safetyIndicators")) {
|
|
return this.generateSafetyIndicatorsResponse(toolName, parameters);
|
|
}
|
|
|
|
if (toolName.includes("medicalRecords")) {
|
|
return this.generateMedicalRecordsResponse(toolName, parameters);
|
|
}
|
|
|
|
if (toolName.includes("addTask")) {
|
|
return this.generateTaskResponse(toolName, parameters);
|
|
}
|
|
|
|
if (toolName.includes("addVital")) {
|
|
return this.generateVitalSignsResponse(toolName, parameters);
|
|
}
|
|
|
|
// Patient management responses
|
|
if (toolName.includes("Patient") || toolName.includes("patient")) {
|
|
return this.generatePatientResponse(toolName, parameters);
|
|
}
|
|
|
|
// Password management responses
|
|
if (toolName.includes("Password") || toolName.includes("password")) {
|
|
return this.generatePasswordResponse(toolName, parameters);
|
|
}
|
|
|
|
// Medicine template responses
|
|
if (toolName.includes("medicine_template")) {
|
|
return this.generateMedicineTemplateResponse(toolName, parameters);
|
|
}
|
|
|
|
// Medicine import responses
|
|
if (toolName.includes("importMedicine")) {
|
|
return this.generateMedicineImportResponse(toolName, parameters);
|
|
}
|
|
|
|
// Appointment management responses
|
|
if (toolName.includes("appointmentParticipant")) {
|
|
return this.generateAppointmentParticipantResponse(toolName, parameters);
|
|
}
|
|
|
|
if (toolName.includes("availableSlot")) {
|
|
return this.generateAvailableSlotsResponse(toolName, parameters);
|
|
}
|
|
|
|
if (toolName.includes("BookAppointment")) {
|
|
return this.generateBookAppointmentResponse(toolName, parameters);
|
|
}
|
|
|
|
// Login responses
|
|
if (toolName.includes("login") || toolName.includes("Login")) {
|
|
return this.generateLoginResponse(toolName, parameters);
|
|
}
|
|
|
|
// Registration responses
|
|
if (toolName.includes("register") || toolName.includes("Register")) {
|
|
return this.generateRegistrationResponse(toolName, parameters);
|
|
}
|
|
|
|
// Default response
|
|
return {
|
|
success: true,
|
|
data: {
|
|
message: `Mock execution of ${toolName}`,
|
|
parameters: parameters,
|
|
timestamp: new Date().toISOString(),
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Check for error scenarios based on parameters
|
|
* @param {string} toolName - Name of the tool
|
|
* @param {Object} parameters - Tool parameters
|
|
* @returns {Error|null} Error object if error scenario detected
|
|
*/
|
|
checkForErrorScenarios(toolName, parameters) {
|
|
// Authentication errors
|
|
if (this.shouldSimulateAuthError(toolName, parameters)) {
|
|
return new Error("Authentication required");
|
|
}
|
|
|
|
// Malformed response errors
|
|
if (this.shouldSimulateMalformedResponse(toolName, parameters)) {
|
|
return new Error(
|
|
"Invalid response format: Unable to parse server response"
|
|
);
|
|
}
|
|
|
|
// Validation errors
|
|
if (this.shouldSimulateValidationError(toolName, parameters)) {
|
|
// Check for expired tokens first
|
|
if (
|
|
parameters.token === "expired_token_456" ||
|
|
parameters.token === "expired_token"
|
|
) {
|
|
return new Error("Reset token has expired");
|
|
}
|
|
|
|
// Check for invalid tokens
|
|
if (
|
|
parameters.token === "invalid_token" ||
|
|
parameters.token === "invalid_token_123"
|
|
) {
|
|
return new Error("Invalid request");
|
|
}
|
|
|
|
// Check for password confirmation mismatch
|
|
if (
|
|
parameters.password &&
|
|
parameters.password_confirmation &&
|
|
parameters.password !== parameters.password_confirmation
|
|
) {
|
|
return new Error("Password confirmation does not match");
|
|
}
|
|
|
|
// Check for invalid appointment IDs
|
|
if (parameters.appointmentId === "invalid_appointment") {
|
|
return new Error("Appointment not found");
|
|
}
|
|
|
|
// Check for invalid date formats
|
|
if (parameters.date === "invalid-date-format") {
|
|
return new Error("Invalid date format");
|
|
}
|
|
|
|
// Check for scheduling conflicts
|
|
if (
|
|
parameters.date === "2025-07-15" &&
|
|
parameters.time === "14:00" &&
|
|
parameters.patient_id === "patient_123"
|
|
) {
|
|
return new Error("Scheduling conflict detected");
|
|
}
|
|
|
|
// Check for invalid file format
|
|
if (
|
|
(toolName.includes("importMedicine") ||
|
|
toolName.includes("emrimportMedicine")) &&
|
|
parameters.excel_file &&
|
|
parameters.excel_file.type !==
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
) {
|
|
return new Error(
|
|
"Invalid file format. Only Excel files are supported."
|
|
);
|
|
}
|
|
|
|
// Check for login errors
|
|
if (toolName.includes("login") || toolName.includes("Login")) {
|
|
const loginIdentifier = parameters.username || parameters.email;
|
|
|
|
// Invalid credentials
|
|
if (
|
|
loginIdentifier === "invaliduser" ||
|
|
parameters.password === "wrongpassword"
|
|
) {
|
|
return new Error("Invalid credentials");
|
|
}
|
|
|
|
// Missing required fields
|
|
if (!loginIdentifier || !parameters.password) {
|
|
return new Error("Username/email and password are required");
|
|
}
|
|
|
|
// Rate limiting
|
|
if (
|
|
loginIdentifier === "testuser" &&
|
|
parameters.password === "testpassword"
|
|
) {
|
|
return new Error("Too many login attempts. Please try again later.");
|
|
}
|
|
}
|
|
|
|
// Check for prescription validation errors
|
|
if (toolName.includes("prescription")) {
|
|
// Missing required prescription fields
|
|
if (
|
|
parameters.medication_data &&
|
|
(!parameters.medication_data.medication_name ||
|
|
!parameters.medication_data.strength ||
|
|
!parameters.medication_data.dosage ||
|
|
!parameters.medication_data.frequency)
|
|
) {
|
|
return new Error("Missing required prescription fields");
|
|
}
|
|
|
|
// Invalid dosage format
|
|
if (parameters.medication_data?.dosage === "invalid_dosage") {
|
|
return new Error("Invalid dosage format");
|
|
}
|
|
}
|
|
|
|
// Check for password reset rate limiting
|
|
if (
|
|
toolName.includes("forgotPassword") ||
|
|
toolName.includes("passwordReset")
|
|
) {
|
|
// Rate limit for specific email only in rate limiting test context
|
|
if (parameters.email === "ratelimited@test.com") {
|
|
return new Error(
|
|
"Too many password reset attempts. Please try again later."
|
|
);
|
|
}
|
|
|
|
// Rate limit for multiple attempts from same IP (simulated)
|
|
if (parameters.email && parameters.email.includes("ratelimited")) {
|
|
return new Error(
|
|
"Rate limit exceeded. Too many password reset requests."
|
|
);
|
|
}
|
|
}
|
|
|
|
// Check for input sanitization violations
|
|
for (const [key, value] of Object.entries(parameters)) {
|
|
if (typeof value === "string") {
|
|
// Check for XSS attempts
|
|
if (
|
|
value.includes("<script>") ||
|
|
value.includes("</script>") ||
|
|
value.includes("javascript:") ||
|
|
value.includes("onload=") ||
|
|
value.includes("onerror=") ||
|
|
value.includes("onclick=")
|
|
) {
|
|
return new Error(
|
|
"Invalid input detected. Malicious content not allowed."
|
|
);
|
|
}
|
|
|
|
// Check for SQL injection attempts
|
|
if (
|
|
value.includes("'; DROP TABLE") ||
|
|
value.includes("' OR '1'='1") ||
|
|
value.includes("UNION SELECT") ||
|
|
value.includes("-- ")
|
|
) {
|
|
return new Error(
|
|
"Invalid input detected. SQL injection attempts not allowed."
|
|
);
|
|
}
|
|
|
|
// Check for path traversal attempts
|
|
if (
|
|
value.includes("../") ||
|
|
value.includes("..\\") ||
|
|
value.includes("/etc/passwd") ||
|
|
value.includes("C:\\Windows")
|
|
) {
|
|
return new Error(
|
|
"Invalid input detected. Path traversal attempts not allowed."
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use generic error message for security-sensitive operations
|
|
if (toolName.includes("Password") || toolName.includes("password")) {
|
|
return new Error("Invalid request");
|
|
}
|
|
return new Error("Validation failed");
|
|
}
|
|
|
|
// Patient not found errors
|
|
if (this.shouldSimulateNotFoundError(toolName, parameters)) {
|
|
return new Error("Patient not found");
|
|
}
|
|
|
|
// Permission errors
|
|
if (this.shouldSimulatePermissionError(toolName, parameters)) {
|
|
return new Error("Insufficient permissions");
|
|
}
|
|
|
|
// Rate limiting errors
|
|
if (this.shouldSimulateRateLimitError(toolName, parameters)) {
|
|
return new Error("Rate limit exceeded");
|
|
}
|
|
|
|
// Medical safety errors
|
|
if (this.shouldSimulateMedicalSafetyError(toolName, parameters)) {
|
|
// Provide specific error messages for different safety violations
|
|
if (
|
|
parameters.medication_data?.medication_name === "Aspirin" &&
|
|
parameters.medication_data?.patient_age < 18
|
|
) {
|
|
return new Error(
|
|
"Age-related contraindication: Aspirin not recommended for pediatric patients"
|
|
);
|
|
}
|
|
|
|
if (
|
|
parameters.medication_data?.medication_name === "Penicillin" &&
|
|
parameters.medication_data?.patient_allergies?.includes("Penicillin")
|
|
) {
|
|
return new Error("Allergy contraindication detected");
|
|
}
|
|
|
|
return new Error("Medical safety violation");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Check if should simulate authentication error
|
|
*/
|
|
shouldSimulateAuthError(toolName, parameters) {
|
|
// Check if HTTP mocks indicate an authentication error (401 status)
|
|
if (this.httpMocks && this.httpMocks.mocks) {
|
|
for (const [key, mock] of this.httpMocks.mocks) {
|
|
if (mock.response && mock.response.status === 401) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Only simulate auth errors for explicit test scenarios
|
|
if (
|
|
parameters.simulate_auth_error ||
|
|
parameters.unauthenticated ||
|
|
(parameters.patientId &&
|
|
parameters.patientId === "unauthorized_patient") ||
|
|
toolName.includes("unauthorized") ||
|
|
parameters.no_auth_token
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Check for specific authentication test scenarios
|
|
if (this.isAuthenticationTestScenario(toolName, parameters)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if should simulate malformed response error
|
|
* @param {string} toolName - Tool name
|
|
* @param {Object} parameters - Tool parameters
|
|
* @returns {boolean}
|
|
*/
|
|
shouldSimulateMalformedResponse(toolName, parameters) {
|
|
// Check if HTTP mocks have malformed response data
|
|
if (this.httpMocks && this.httpMocks.mocks) {
|
|
for (const [key, mock] of this.httpMocks.mocks) {
|
|
if (
|
|
mock.response &&
|
|
typeof mock.response.data === "string" &&
|
|
mock.response.data === "invalid json response"
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if should simulate validation error
|
|
*/
|
|
shouldSimulateValidationError(toolName, parameters) {
|
|
// Only simulate validation errors for explicitly invalid test data
|
|
|
|
// Check for explicitly invalid emails (test emails should be valid)
|
|
if (parameters.email && parameters.email.includes("invalid-email")) {
|
|
return true;
|
|
}
|
|
|
|
if (
|
|
parameters.emailAddress &&
|
|
parameters.emailAddress.includes("invalid-email")
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Only check password confirmation mismatch for explicit test cases
|
|
if (
|
|
parameters.password &&
|
|
parameters.confirm_password &&
|
|
parameters.password !== parameters.confirm_password &&
|
|
parameters.password !== "123" // Allow weak passwords for testing
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Password confirmation mismatch (alternative parameter name)
|
|
if (
|
|
parameters.password &&
|
|
parameters.password_confirmation &&
|
|
parameters.password !== parameters.password_confirmation &&
|
|
parameters.password !== "123" // Allow weak passwords for testing
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Password strength validation for password-related tools
|
|
if (
|
|
toolName.includes("Password") ||
|
|
toolName.includes("password") ||
|
|
toolName.includes("setPassword") ||
|
|
toolName.includes("resetPassword")
|
|
) {
|
|
// Check for weak passwords that should fail validation
|
|
if (parameters.password && !this.isValidPassword(parameters.password)) {
|
|
return true;
|
|
}
|
|
|
|
if (
|
|
parameters.new_password &&
|
|
!this.isValidPassword(parameters.new_password)
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
if (
|
|
parameters.newPassword &&
|
|
!this.isValidPassword(parameters.newPassword)
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Invalid reset tokens
|
|
if (
|
|
parameters.token === "invalid_token" ||
|
|
parameters.reset_token === "invalid_token"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Expired tokens
|
|
if (
|
|
parameters.token === "expired_token" ||
|
|
parameters.token === "expired_token_456" ||
|
|
parameters.reset_token === "expired_token"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
if (parameters.record_type === "invalid_type") {
|
|
return true;
|
|
}
|
|
|
|
// Missing required fields for patient registration
|
|
if (toolName.includes("register")) {
|
|
// Check for missing required patient registration fields
|
|
const requiredFields = ["firstName", "lastName", "email", "dateOfBirth"];
|
|
for (const field of requiredFields) {
|
|
if (!parameters[field]) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Invalid dosage for prescriptions
|
|
if (parameters.medication_data?.dosage === "invalid_dosage") {
|
|
return true;
|
|
}
|
|
|
|
// Missing template data
|
|
if (
|
|
toolName.includes("template") &&
|
|
!parameters.template_data?.medication_name
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Appointment validation errors
|
|
if (parameters.appointmentId === "invalid_appointment") {
|
|
return true;
|
|
}
|
|
|
|
// Invalid date format
|
|
if (parameters.date === "invalid-date-format") {
|
|
return true;
|
|
}
|
|
|
|
// Scheduling conflicts
|
|
if (
|
|
parameters.date === "2025-07-15" &&
|
|
parameters.time === "14:00" &&
|
|
parameters.patient_id === "patient_123"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Note: File format validation for medicine import is now handled by shouldSimulateFileFormatError
|
|
|
|
// Login validation errors
|
|
if (toolName.includes("login") || toolName.includes("Login")) {
|
|
const loginIdentifier = parameters.username || parameters.email;
|
|
|
|
// Invalid credentials
|
|
if (
|
|
loginIdentifier === "invaliduser" ||
|
|
parameters.password === "wrongpassword"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Missing required fields
|
|
if (!loginIdentifier || !parameters.password) {
|
|
return true;
|
|
}
|
|
|
|
// Rate limiting for specific user
|
|
if (
|
|
loginIdentifier === "testuser" &&
|
|
parameters.password === "testpassword"
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Prescription validation errors (only for prescription store operations with explicit validation test)
|
|
if (
|
|
toolName.includes("prescriptionstore") &&
|
|
parameters.test_validation === true
|
|
) {
|
|
// Missing required prescription fields
|
|
if (
|
|
parameters.medication_data &&
|
|
(!parameters.medication_data.medication_name ||
|
|
!parameters.medication_data.strength ||
|
|
!parameters.medication_data.dosage ||
|
|
!parameters.medication_data.frequency)
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Invalid dosage format
|
|
if (parameters.medication_data?.dosage === "invalid_dosage") {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Password reset rate limiting
|
|
if (
|
|
toolName.includes("forgotPassword") ||
|
|
toolName.includes("passwordReset")
|
|
) {
|
|
// Rate limit for specific email only in rate limiting test context
|
|
if (parameters.email === "ratelimited@test.com") {
|
|
return true;
|
|
}
|
|
|
|
// Rate limit for multiple attempts from same IP (simulated)
|
|
if (parameters.email && parameters.email.includes("ratelimited")) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Input sanitization validation - check for malicious content
|
|
for (const [key, value] of Object.entries(parameters)) {
|
|
if (typeof value === "string") {
|
|
// Check for XSS attempts
|
|
if (
|
|
value.includes("<script>") ||
|
|
value.includes("</script>") ||
|
|
value.includes("javascript:") ||
|
|
value.includes("onload=") ||
|
|
value.includes("onerror=") ||
|
|
value.includes("onclick=")
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Check for SQL injection attempts
|
|
if (
|
|
value.includes("'; DROP TABLE") ||
|
|
value.includes("' OR '1'='1") ||
|
|
value.includes("UNION SELECT") ||
|
|
value.includes("-- ")
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Check for path traversal attempts
|
|
if (
|
|
value.includes("../") ||
|
|
value.includes("..\\") ||
|
|
value.includes("/etc/passwd") ||
|
|
value.includes("C:\\Windows")
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if should simulate not found error
|
|
*/
|
|
shouldSimulateNotFoundError(toolName, parameters) {
|
|
if (
|
|
parameters.patientId === 999999 ||
|
|
parameters.patient_id === "nonexistent_patient" ||
|
|
parameters.id === 999999
|
|
) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if should simulate permission error
|
|
*/
|
|
shouldSimulatePermissionError(toolName, parameters) {
|
|
// Check if HTTP mocks indicate a permission error (403 status)
|
|
if (this.httpMocks && this.httpMocks.mocks) {
|
|
for (const [key, mock] of this.httpMocks.mocks) {
|
|
if (mock.response && mock.response.status === 403) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (
|
|
parameters.simulate_permission_error ||
|
|
parameters.insufficient_permissions ||
|
|
(parameters.patientId && parameters.patientId === "restricted_patient")
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Controlled substance prescriptions without DEA authorization
|
|
if (
|
|
toolName.includes("prescription") &&
|
|
parameters.medication_data?.dea_schedule &&
|
|
parameters.medication_data.dea_schedule !== "Non-controlled" &&
|
|
!parameters.dea_authorized &&
|
|
!parameters.medication_data.prescriber_dea
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Patient data access without proper role
|
|
if (
|
|
toolName.includes("Patient") &&
|
|
parameters.user_role === "unauthorized_role"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Cross-patient access violations
|
|
if (
|
|
parameters.patientId &&
|
|
parameters.accessing_user_id &&
|
|
parameters.patientId !== parameters.accessing_user_id &&
|
|
!parameters.provider_access
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// EMR operations without proper credentials
|
|
if (toolName.includes("emr") && parameters.insufficient_credentials) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if should simulate rate limit error
|
|
*/
|
|
shouldSimulateRateLimitError(toolName, parameters) {
|
|
if (
|
|
parameters.simulate_rate_limit ||
|
|
(toolName.includes("prescription") && parameters.rapid_requests)
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Rate limit password reset attempts
|
|
if (
|
|
toolName.includes("forgot") &&
|
|
parameters.email === "ratelimited@test.com"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if should simulate medical safety error
|
|
*/
|
|
shouldSimulateMedicalSafetyError(toolName, parameters) {
|
|
// Allergy contraindications
|
|
if (
|
|
parameters.medication_data?.medication_name === "Penicillin" &&
|
|
parameters.medication_data?.patient_allergies?.includes("Penicillin")
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Pediatric dosage errors - check both patientId and patient_age
|
|
if (
|
|
(parameters.patientId === "pediatric_patient" ||
|
|
parameters.medication_data?.patient_age < 18) &&
|
|
parameters.medication_data?.medication_name === "Aspirin"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Age-related contraindications for specific medications
|
|
if (
|
|
parameters.medication_data?.patient_age &&
|
|
parameters.medication_data?.patient_age < 18
|
|
) {
|
|
// Aspirin contraindicated in pediatric patients (Reye's syndrome risk)
|
|
if (parameters.medication_data?.medication_name === "Aspirin") {
|
|
return true;
|
|
}
|
|
|
|
// Other pediatric contraindications can be added here
|
|
if (
|
|
parameters.medication_data?.medication_name === "Tetracycline" &&
|
|
parameters.medication_data?.patient_age < 8
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Geriatric dosage concerns
|
|
if (
|
|
parameters.medication_data?.patient_age &&
|
|
parameters.medication_data?.patient_age > 65
|
|
) {
|
|
// High-dose medications in elderly
|
|
if (
|
|
parameters.medication_data?.medication_name === "Digoxin" &&
|
|
parseFloat(parameters.medication_data?.dosage) > 0.25
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Invalid vital signs
|
|
if (parameters.temperature > 110 || parameters.temperature < 95) {
|
|
return true;
|
|
}
|
|
|
|
// Inactive patient prescriptions
|
|
if (parameters.patient_id === "inactive_patient") {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if should simulate file format error
|
|
*/
|
|
shouldSimulateFileFormatError(toolName, parameters) {
|
|
// File format validation errors for medicine import
|
|
if (
|
|
toolName === "provider_create_emrimportMedicine" &&
|
|
parameters.excel_file
|
|
) {
|
|
const fileName = parameters.excel_file.name || parameters.excel_file;
|
|
if (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls")) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return (
|
|
(toolName.includes("import") || toolName.includes("upload")) &&
|
|
parameters.file &&
|
|
!parameters.file.endsWith(".xlsx") &&
|
|
!parameters.file.endsWith(".xls") &&
|
|
!parameters.file.endsWith(".csv")
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get the expected HTTP endpoint for a given tool
|
|
* @param {string} toolName - Name of the tool
|
|
* @param {Object} parameters - Tool parameters
|
|
* @returns {string} Expected endpoint
|
|
*/
|
|
getExpectedEndpointForTool(toolName, parameters) {
|
|
// Map tool names to their expected HTTP endpoints
|
|
const toolEndpointMap = {
|
|
// Prescription tools
|
|
provider_create_prescriptionstore: `/api/emr/prescription/store/${
|
|
parameters.patient_id || "patient_123"
|
|
}`,
|
|
provider_create_emrimportMedicine: "/api/emr/import/medicine",
|
|
|
|
// Patient management tools
|
|
provider_create_emrregisterPatient: "/api/emr/patients",
|
|
provider_create_emrupdatePatient: `/api/emr/patients/${
|
|
parameters.patient_id || parameters.id
|
|
}`,
|
|
provider_create_getPatientInfo: `/api/emr/patients/${
|
|
parameters.patient_id || parameters.id
|
|
}`,
|
|
provider_create_updatePatientInfo: `/api/emr/patients/${
|
|
parameters.patient_id || parameters.id
|
|
}`,
|
|
|
|
// Medical records
|
|
provider_create_medicalRecordscreate: "/api/emr/medical-records",
|
|
provider_create_addVital: "/api/emr/vital-signs",
|
|
|
|
// Public tools
|
|
public_create_login: "/api/login",
|
|
public_create_frontendlogin: "/api/frontend/login",
|
|
public_create_adminlogin: "/api/admin/login",
|
|
|
|
// Default patterns
|
|
default: this.getDefaultEndpointForTool(toolName, parameters),
|
|
};
|
|
|
|
return toolEndpointMap[toolName] || toolEndpointMap.default;
|
|
}
|
|
|
|
/**
|
|
* Get default endpoint pattern for a tool
|
|
* @param {string} toolName - Name of the tool
|
|
* @param {Object} parameters - Tool parameters
|
|
* @returns {string} Default endpoint
|
|
*/
|
|
getDefaultEndpointForTool(toolName, parameters) {
|
|
// Extract endpoint pattern from tool name
|
|
if (toolName.startsWith("provider_")) {
|
|
return (
|
|
"/api/emr/" +
|
|
toolName.replace("provider_create_", "").replace("provider_", "")
|
|
);
|
|
} else if (toolName.startsWith("public_")) {
|
|
return (
|
|
"/api/" + toolName.replace("public_create_", "").replace("public_", "")
|
|
);
|
|
} else if (toolName.startsWith("patient_")) {
|
|
return (
|
|
"/api/patient/" +
|
|
toolName.replace("patient_create_", "").replace("patient_", "")
|
|
);
|
|
}
|
|
|
|
return "/api/" + toolName;
|
|
}
|
|
|
|
/**
|
|
* Check if an HTTP mock is relevant for the current tool execution
|
|
* @param {string} mockKey - HTTP mock key (e.g., "POST:/api/emr/prescription/store/patient_123")
|
|
* @param {string} expectedEndpoint - Expected endpoint for the tool
|
|
* @param {string} toolName - Name of the tool
|
|
* @returns {boolean} Whether the mock is relevant
|
|
*/
|
|
isHttpMockRelevantForTool(mockKey, expectedEndpoint, toolName) {
|
|
// Extract method and URL from mock key
|
|
const [method, url] = mockKey.split(":");
|
|
|
|
// Check for exact match first
|
|
if (url === expectedEndpoint) {
|
|
return true;
|
|
}
|
|
|
|
// Check for pattern matches
|
|
if (expectedEndpoint && url) {
|
|
// Handle dynamic parameters in URLs (e.g., patient IDs)
|
|
const expectedPattern = expectedEndpoint
|
|
.replace(/\/\d+/g, "/\\d+")
|
|
.replace(/\/[a-zA-Z0-9_-]+/g, "/[a-zA-Z0-9_-]+");
|
|
const urlPattern = url
|
|
.replace(/\/\d+/g, "/\\d+")
|
|
.replace(/\/[a-zA-Z0-9_-]+/g, "/[a-zA-Z0-9_-]+");
|
|
|
|
if (expectedPattern === urlPattern) {
|
|
return true;
|
|
}
|
|
|
|
// Check if URLs have similar patterns
|
|
if (
|
|
url.includes(expectedEndpoint.split("/").slice(0, -1).join("/")) ||
|
|
expectedEndpoint.includes(url.split("/").slice(0, -1).join("/"))
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Validate email format
|
|
*/
|
|
isValidEmail(email) {
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return emailRegex.test(email);
|
|
}
|
|
|
|
/**
|
|
* Validate password strength
|
|
*/
|
|
isValidPassword(password) {
|
|
// For testing purposes, validate common weak passwords
|
|
if (!password || password.length < 6) {
|
|
return false;
|
|
}
|
|
|
|
// Reject common weak passwords that tests expect to fail
|
|
const weakPasswords = [
|
|
"123",
|
|
"123456",
|
|
"password",
|
|
"weak",
|
|
"simple",
|
|
"test",
|
|
"abc123",
|
|
"qwerty",
|
|
"admin",
|
|
"user",
|
|
"invalid",
|
|
"bad",
|
|
"explicitly-invalid-password",
|
|
];
|
|
|
|
if (weakPasswords.includes(password.toLowerCase())) {
|
|
return false;
|
|
}
|
|
|
|
// For testing, accept passwords with reasonable length and complexity
|
|
return password.length >= 6;
|
|
}
|
|
|
|
/**
|
|
* Check if this is an authentication test scenario
|
|
*/
|
|
isAuthenticationTestScenario(toolName, parameters) {
|
|
// Look for test patterns that indicate authentication should fail
|
|
|
|
// Explicit test failure flag
|
|
if (parameters.test_auth_failure === true) {
|
|
return true;
|
|
}
|
|
|
|
// Invalid credentials patterns
|
|
if (
|
|
parameters.username === "invalid_user" ||
|
|
parameters.email === "invalid@test.com"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
if (
|
|
parameters.password === "wrong_password" ||
|
|
parameters.password === "invalid"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Account status issues
|
|
if (
|
|
parameters.username === "locked_user" ||
|
|
parameters.email === "locked@test.com"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
if (
|
|
parameters.username === "disabled_user" ||
|
|
parameters.email === "disabled@test.com"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Expired token scenarios
|
|
if (
|
|
parameters.token === "expired_token" ||
|
|
parameters.access_token === "expired_token"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Unauthorized access patterns
|
|
if (parameters.unauthorized === true || parameters.no_permission === true) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Generate prescription-specific responses
|
|
*/
|
|
generatePrescriptionResponse(toolName, parameters) {
|
|
const medicationName =
|
|
parameters.medication_data?.medication_name || "Lisinopril";
|
|
const alerts = [];
|
|
|
|
// Generate specific clinical alerts based on medication
|
|
if (medicationName === "Warfarin" || medicationName === "Digoxin") {
|
|
alerts.push({
|
|
type: "dosage_adjustment",
|
|
severity: "moderate",
|
|
reason: "renal_impairment_elderly",
|
|
current_dose: parameters.medication_data?.dosage || "0.25mg daily",
|
|
recommended_dose: "0.125mg daily",
|
|
adjustment_factor: 0.5,
|
|
monitoring_required: ["serum_digoxin_levels", "kidney_function"],
|
|
rationale:
|
|
"Reduced clearance in elderly patients with renal impairment",
|
|
});
|
|
}
|
|
|
|
// Add drug interaction alerts for multiple medications
|
|
if (parameters.medication_data?.current_medications?.length > 0) {
|
|
alerts.push({
|
|
type: "drug_interaction",
|
|
severity: "major",
|
|
interaction: "Warfarin + Aspirin",
|
|
description: "Increased risk of bleeding",
|
|
recommendation:
|
|
"Monitor INR closely, consider alternative antiplatelet therapy",
|
|
evidence_level: "high",
|
|
references: ["Clinical Pharmacology Database"],
|
|
});
|
|
|
|
alerts.push({
|
|
type: "drug_interaction",
|
|
severity: "moderate",
|
|
interaction: "Warfarin + Ibuprofen",
|
|
description: "Increased anticoagulant effect",
|
|
recommendation: "Avoid concurrent use or monitor INR",
|
|
evidence_level: "moderate",
|
|
});
|
|
} else {
|
|
// Single drug interaction alert for basic scenarios
|
|
alerts.push({
|
|
type: "drug_interaction",
|
|
severity: "major",
|
|
interaction: "Warfarin + Aspirin",
|
|
description: "Increased risk of bleeding",
|
|
recommendation:
|
|
"Monitor INR closely, consider alternative antiplatelet therapy",
|
|
});
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
prescription: {
|
|
id: `prescription_${Math.random().toString(36).substr(2, 9)}`,
|
|
patientId: parameters.patient_id,
|
|
medication: {
|
|
name: medicationName,
|
|
strength: parameters.medication_data?.strength || "10mg",
|
|
},
|
|
dosage: parameters.medication_data?.dosage || "10mg",
|
|
frequency: parameters.medication_data?.frequency || "Once daily",
|
|
controlledSubstance: parameters.medication_data?.dea_schedule
|
|
? true
|
|
: false,
|
|
refills: parameters.medication_data?.dea_schedule ? 0 : 2,
|
|
},
|
|
clinical_alerts: alerts,
|
|
warnings: [
|
|
{
|
|
type: "drug_interaction",
|
|
severity: "moderate",
|
|
message: "Check for drug interactions",
|
|
},
|
|
],
|
|
auditTrail: {
|
|
accessId: `audit_${Math.random().toString(36).substr(2, 9)}`,
|
|
userId: "provider_456",
|
|
action: "prescription_created",
|
|
prescriberId: "provider_456",
|
|
timestamp: new Date().toISOString(),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate medicine import responses
|
|
*/
|
|
generateMedicineImportResponse(toolName, parameters) {
|
|
// Check for file format validation errors first
|
|
if (this.shouldSimulateFileFormatError(toolName, parameters)) {
|
|
throw new Error(
|
|
"Invalid file format. Only Excel files (.xlsx) are supported for medicine import."
|
|
);
|
|
}
|
|
|
|
// Check for validation errors in import data
|
|
if (parameters.simulate_import_errors) {
|
|
return {
|
|
success: false,
|
|
data: {
|
|
errors: [
|
|
{
|
|
row: 1,
|
|
field: "medication_name",
|
|
message: "Invalid medication name",
|
|
},
|
|
{ row: 2, field: "strength", message: "Invalid strength format" },
|
|
],
|
|
},
|
|
};
|
|
}
|
|
|
|
// Check for validation errors in import file name
|
|
if (
|
|
parameters.excel_file &&
|
|
parameters.excel_file.name &&
|
|
parameters.excel_file.name.includes("invalid")
|
|
) {
|
|
return {
|
|
success: false,
|
|
data: {
|
|
errors: [
|
|
{ row: 2, message: "Invalid medicine name format" },
|
|
{ row: 5, message: "Missing required dosage information" },
|
|
],
|
|
imported_count: 0,
|
|
summary: {
|
|
total_rows: 10,
|
|
successful_imports: 0,
|
|
duplicates_skipped: 0,
|
|
validation_errors: 2,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Successful import response
|
|
return {
|
|
success: true,
|
|
data: {
|
|
imported_count: 150,
|
|
summary: {
|
|
total_rows: 155,
|
|
successful_imports: 150,
|
|
duplicates_skipped: 3,
|
|
validation_errors: 2,
|
|
},
|
|
import_results: {
|
|
imported_medicines: 150,
|
|
total_rows: 155,
|
|
skipped_rows: 5,
|
|
errors: [],
|
|
},
|
|
auditTrail: {
|
|
accessId: `audit_${Math.random().toString(36).substr(2, 9)}`,
|
|
userId: "provider_456",
|
|
action: "medicine_import",
|
|
timestamp: new Date().toISOString(),
|
|
},
|
|
message: "Medicines imported successfully",
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate patient data management responses
|
|
*/
|
|
generatePatientDataResponse(toolName, parameters) {
|
|
// Medical records responses
|
|
if (toolName.includes("medicalRecords")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
medical_records: [
|
|
{
|
|
id: "record_123",
|
|
patientId: "patient_123",
|
|
type: "progress_note",
|
|
date: "2025-07-10",
|
|
provider: "Dr. Smith",
|
|
diagnosis: "Hypertension",
|
|
treatment: "Lisinopril 10mg daily",
|
|
},
|
|
{
|
|
id: "record_124",
|
|
patientId: "patient_123",
|
|
type: "lab_result",
|
|
date: "2025-07-05",
|
|
provider: "Lab Tech",
|
|
results: "Blood pressure: 140/90",
|
|
},
|
|
],
|
|
total_count: 2,
|
|
filters_applied: {
|
|
start_date: parameters.start_date || "2025-01-01",
|
|
end_date: parameters.end_date || "2025-12-31",
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Prescriptions responses
|
|
if (toolName.includes("prescriptions")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
prescriptions: [
|
|
{
|
|
id: "rx_123",
|
|
medication: { name: "Lisinopril", strength: "10mg" },
|
|
dosage: "Once daily",
|
|
status: parameters.status || "active",
|
|
prescriber: "Dr. Smith",
|
|
date_prescribed: "2025-07-01",
|
|
},
|
|
{
|
|
id: "rx_124",
|
|
medication: { name: "Metformin", strength: "500mg" },
|
|
dosage: "Twice daily",
|
|
status: "active",
|
|
prescriber: "Dr. Johnson",
|
|
date_prescribed: "2025-06-15",
|
|
},
|
|
],
|
|
active_count: 2,
|
|
filters_applied: {
|
|
status: parameters.status || "all",
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Appointments responses
|
|
if (toolName.includes("appointments") || toolName.includes("Appointment")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
appointments: [
|
|
{
|
|
id: "appt_123",
|
|
patientId: "patient_123",
|
|
practitioner: "Dr. Smith",
|
|
date: "2025-07-15",
|
|
time: "10:00 AM",
|
|
status: "scheduled",
|
|
type: "follow-up",
|
|
},
|
|
{
|
|
id: "appt_124",
|
|
patientId: "patient_123",
|
|
practitioner: "Dr. Johnson",
|
|
date: "2025-07-20",
|
|
time: "2:00 PM",
|
|
status: "scheduled",
|
|
type: "consultation",
|
|
},
|
|
],
|
|
upcoming_count: 2,
|
|
confirmation_number: "CONF123456",
|
|
},
|
|
};
|
|
}
|
|
|
|
// Profile update responses
|
|
if (toolName.includes("updatePatientProfile")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
patient: {
|
|
id: "patient_123",
|
|
firstName: parameters.firstName || "John",
|
|
lastName: parameters.lastName || "Doe",
|
|
email: parameters.email || "john.doe@example.com",
|
|
phone: parameters.phone || "555-0123",
|
|
address: parameters.address || "123 Main St",
|
|
city: parameters.city || "Anytown",
|
|
state: parameters.state || "CA",
|
|
zipcode: parameters.zipcode || "12345",
|
|
dateOfBirth: "1980-01-01",
|
|
lastUpdated: new Date().toISOString(),
|
|
},
|
|
auditTrail: {
|
|
action: "profile_updated",
|
|
timestamp: new Date().toISOString(),
|
|
updatedBy: "patient_123",
|
|
changes: Object.keys(parameters).filter(
|
|
(key) => key !== "patient_id"
|
|
),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Default patient response
|
|
return this.generatePatientResponse(toolName, parameters);
|
|
}
|
|
|
|
/**
|
|
* Generate provider EMR management responses
|
|
*/
|
|
generateProviderEMRResponse(toolName, parameters) {
|
|
// Medical record creation
|
|
if (toolName.includes("medicalRecordscreate")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
medical_record: {
|
|
id: "record_456",
|
|
patientId: parameters.patient_id || "patient_123",
|
|
type: parameters.record_type || "progress_note",
|
|
content: parameters.content || "Patient visit notes",
|
|
created_by: "provider_456",
|
|
created_at: new Date().toISOString(),
|
|
},
|
|
auditTrail: {
|
|
action: "medical_record_created",
|
|
timestamp: new Date().toISOString(),
|
|
providerId: "provider_456",
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Get patient info
|
|
if (toolName.includes("getPatientInfo")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
patient: {
|
|
id: parameters.patient_id || "patient_123",
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
email: "john.doe@example.com",
|
|
phone: "555-0123",
|
|
dateOfBirth: "1980-01-01",
|
|
address: "123 Main St",
|
|
city: "Anytown",
|
|
state: "CA",
|
|
zipcode: "12345",
|
|
medicalHistory: ["Hypertension", "Diabetes"],
|
|
allergies: ["Penicillin"],
|
|
currentMedications: ["Lisinopril 10mg", "Metformin 500mg"],
|
|
hipaaMetadata: {
|
|
dataClassification: "PHI",
|
|
encryptionStatus: "encrypted",
|
|
accessLevel: "restricted",
|
|
},
|
|
},
|
|
auditTrail: {
|
|
action: "patient_info_accessed",
|
|
timestamp: new Date().toISOString(),
|
|
accessedBy: "provider_456",
|
|
purpose: "patient_care",
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Update patient info
|
|
if (toolName.includes("updatePatientInfo")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
patient: {
|
|
id: parameters.patient_id || "patient_123",
|
|
firstName: parameters.firstName || "John",
|
|
lastName: parameters.lastName || "Doe",
|
|
email: parameters.email || "john.doe@example.com",
|
|
phone: parameters.phone || "555-0123",
|
|
address: parameters.address || "123 Main St",
|
|
city: parameters.city || "Anytown",
|
|
state: parameters.state || "CA",
|
|
zipcode: parameters.zipcode || "12345",
|
|
lastUpdated: new Date().toISOString(),
|
|
},
|
|
auditTrail: {
|
|
action: "patient_info_updated",
|
|
timestamp: new Date().toISOString(),
|
|
updatedBy: "provider_456",
|
|
changes: Object.keys(parameters).filter(
|
|
(key) => key !== "patient_id"
|
|
),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Default provider response
|
|
return this.generatePatientResponse(toolName, parameters);
|
|
}
|
|
|
|
/**
|
|
* Generate HIPAA compliance responses
|
|
*/
|
|
generateHIPAAComplianceResponse(toolName, parameters) {
|
|
// PHI encryption and handling
|
|
if (toolName.includes("encrypt") || toolName.includes("phi")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
patient: {
|
|
id: "patient_123",
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
hipaaMetadata: {
|
|
dataClassification: "PHI",
|
|
encryptionStatus: "encrypted",
|
|
accessLevel: "restricted",
|
|
},
|
|
},
|
|
encryption: {
|
|
algorithm: "AES-256",
|
|
status: "encrypted",
|
|
keyManagement: "HSM",
|
|
},
|
|
auditTrail: {
|
|
action: "phi_access",
|
|
timestamp: new Date().toISOString(),
|
|
accessedBy: "provider_456",
|
|
purpose: "patient_care",
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// De-identification for research
|
|
if (
|
|
toolName.includes("deidentification") ||
|
|
toolName.includes("research")
|
|
) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
deidentification: {
|
|
method: "safe_harbor",
|
|
identifiers_removed: ["name", "address", "phone", "ssn"],
|
|
},
|
|
research_data: [
|
|
{
|
|
patient_id: "DEIDENT_001",
|
|
age_group: "50-60",
|
|
diagnosis: "diabetes",
|
|
},
|
|
],
|
|
},
|
|
};
|
|
}
|
|
|
|
// Audit trail responses
|
|
if (toolName.includes("audit")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
auditTrail: {
|
|
accessType: "patient_portal",
|
|
accessedBy: "patient_123",
|
|
timestamp: new Date().toISOString(),
|
|
action: "data_access",
|
|
ipAddress: "192.168.1.100",
|
|
},
|
|
integrity: {
|
|
tamper_detected: false,
|
|
verified_checksums: 1,
|
|
},
|
|
audit_logs: [
|
|
{
|
|
id: "audit_123",
|
|
checksum: "SHA256:abc123def456",
|
|
timestamp: new Date().toISOString(),
|
|
},
|
|
],
|
|
},
|
|
};
|
|
}
|
|
|
|
// Consent verification
|
|
if (toolName.includes("consent")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
consentDetails: {
|
|
dataAccessConsent: true,
|
|
scope: ["medical_records", "treatment_sharing"],
|
|
consentDate: "2025-01-01",
|
|
expirationDate: "2026-01-01",
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Data retention policies
|
|
if (toolName.includes("retention")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
retention_policy: {
|
|
retention_period_years: 7,
|
|
active_records: 5,
|
|
archived_records: 10,
|
|
},
|
|
retention_info: {
|
|
retention_period_years: 7,
|
|
active_records: 5,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Security incident and breach notification
|
|
if (toolName.includes("breach") || toolName.includes("security_incident")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
incident: {
|
|
id: "BREACH_001",
|
|
type: "unauthorized_access_detected",
|
|
severity: "medium",
|
|
affected_records: parameters.affected_records || 50,
|
|
notification_required: true,
|
|
},
|
|
breach_response: {
|
|
immediate_actions: [
|
|
"affected_accounts_locked",
|
|
"security_team_notified",
|
|
"audit_log_preserved",
|
|
],
|
|
notification_timeline: {
|
|
internal_notification: "immediate",
|
|
patient_notification: "within_60_days",
|
|
regulatory_notification: "within_60_days",
|
|
},
|
|
compliance_requirements: [
|
|
"HIPAA_breach_notification_rule",
|
|
"state_breach_notification_laws",
|
|
],
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// BAA compliance and third-party integrations
|
|
if (toolName.includes("baa") || toolName.includes("thirdPartyService")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
baa_compliance: {
|
|
baa_signed: true,
|
|
compliance_verified: true,
|
|
safeguards_required: [
|
|
"encryption",
|
|
"access_controls",
|
|
"audit_logging",
|
|
],
|
|
},
|
|
integration_status: {
|
|
service_name: parameters.service_name || "Third Party Service",
|
|
service_provider:
|
|
parameters.service_provider || "External Provider",
|
|
integration_type: parameters.integration_type || "api_connection",
|
|
compliance_verified: true,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Default HIPAA response
|
|
return this.generatePatientResponse(toolName, parameters);
|
|
}
|
|
|
|
/**
|
|
* Generate public data access responses
|
|
*/
|
|
generatePublicDataAccessResponse(toolName, parameters) {
|
|
// Email check responses
|
|
if (toolName.includes("checkEmail")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
email: parameters.email,
|
|
available: parameters.email !== "existing@test.com",
|
|
suggestions:
|
|
parameters.email === "existing@test.com"
|
|
? ["newuser@test.com"]
|
|
: [],
|
|
},
|
|
};
|
|
}
|
|
|
|
// User check responses
|
|
if (toolName.includes("checkUser")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
username: parameters.username,
|
|
exists: parameters.username !== "nonexistentuser",
|
|
userType:
|
|
parameters.username === "testprovider" ? "provider" : "patient",
|
|
},
|
|
};
|
|
}
|
|
|
|
return this.generatePatientResponse(toolName, parameters);
|
|
}
|
|
|
|
/**
|
|
* Generate appointment and booking responses
|
|
*/
|
|
generateAppointmentResponse(toolName, parameters) {
|
|
// Available slots
|
|
if (toolName.includes("availableSlot")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
date: parameters.date,
|
|
available_slots:
|
|
parameters.date === "2025-07-20"
|
|
? []
|
|
: [
|
|
{ time: "09:00", provider: "Dr. Smith" },
|
|
{ time: "10:00", provider: "Dr. Johnson" },
|
|
{ time: "14:00", provider: "Dr. Smith" },
|
|
],
|
|
},
|
|
};
|
|
}
|
|
|
|
// Book appointment
|
|
if (toolName.includes("BookAppointment")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
appointment: {
|
|
id: "appt_123",
|
|
patient_id: parameters.patient_id,
|
|
date: parameters.date,
|
|
time: parameters.time,
|
|
provider: parameters.provider,
|
|
status: "confirmed",
|
|
},
|
|
confirmation_number: "CONF123456",
|
|
},
|
|
};
|
|
}
|
|
|
|
return this.generatePatientResponse(toolName, parameters);
|
|
}
|
|
|
|
/**
|
|
* Generate email verification responses
|
|
*/
|
|
generateEmailVerificationResponse(toolName, parameters) {
|
|
// Email verification
|
|
if (toolName.includes("verifyEmail")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
email: parameters.email,
|
|
verified: true,
|
|
message: "Email verified successfully",
|
|
},
|
|
};
|
|
}
|
|
|
|
// Resend verification
|
|
if (toolName.includes("resendVerification")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
email: parameters.email,
|
|
message: "Verification email sent successfully",
|
|
},
|
|
};
|
|
}
|
|
|
|
return this.generatePatientResponse(toolName, parameters);
|
|
}
|
|
|
|
/**
|
|
* Generate medical coding responses
|
|
*/
|
|
generateMedicalCodingResponse(toolName, parameters) {
|
|
// ICD-10 coding
|
|
if (toolName.includes("icd10")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
coding_validation: {
|
|
coding_accuracy: 95,
|
|
icd10_codes: [
|
|
{
|
|
code: "E11.9",
|
|
description: "Type 2 diabetes mellitus without complications",
|
|
valid: true,
|
|
},
|
|
],
|
|
billing_compliance: true,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
// CPT coding
|
|
if (toolName.includes("cpt")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
cpt_validation: {
|
|
billing_compliance: true,
|
|
codes: [
|
|
{
|
|
code: "99213",
|
|
description: "Office visit",
|
|
documentation_requirements: [
|
|
"history",
|
|
"examination",
|
|
"decision_making",
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
return this.generatePatientResponse(toolName, parameters);
|
|
}
|
|
|
|
/**
|
|
* Generate clinical handoff responses
|
|
*/
|
|
generateHandoffResponse(toolName, parameters) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
handoff: {
|
|
id: "handoff_123",
|
|
patient_id: parameters.patient_id,
|
|
from_provider: parameters.from_provider,
|
|
to_provider: parameters.to_provider,
|
|
handoff_time: new Date().toISOString(),
|
|
status: "completed",
|
|
acknowledgment_required: true,
|
|
},
|
|
communication_record: {
|
|
sbar_format: {
|
|
situation: "Patient stable, routine monitoring",
|
|
background: "Type 2 diabetes, hypertension",
|
|
assessment: "Stable condition, medications effective",
|
|
recommendation: "Continue current treatment, review labs",
|
|
},
|
|
critical_information_highlighted: true,
|
|
read_back_completed: true,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate care team responses
|
|
*/
|
|
generateCareTeamResponse(toolName, parameters) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
care_team: {
|
|
patient_id: parameters.patient_id,
|
|
team_members: [
|
|
{
|
|
provider_id: "provider_456",
|
|
role: "primary_care_physician",
|
|
status: "active",
|
|
communication_preferences: ["secure_messaging", "phone"],
|
|
},
|
|
{
|
|
provider_id: "provider_789",
|
|
role: "cardiologist",
|
|
status: "active",
|
|
next_appointment: "2025-07-20",
|
|
},
|
|
],
|
|
coordination_plan: {
|
|
communication_protocol: "weekly_updates",
|
|
shared_care_plan: true,
|
|
medication_reconciliation: "monthly",
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate quality measures responses
|
|
*/
|
|
generateQualityMeasuresResponse(toolName, parameters) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
quality_measures: {
|
|
diabetes_care: {
|
|
hba1c_testing: {
|
|
numerator: 85,
|
|
denominator: 100,
|
|
percentage: 85.0,
|
|
benchmark: 90.0,
|
|
status: "below_benchmark",
|
|
},
|
|
blood_pressure_control: {
|
|
numerator: 78,
|
|
denominator: 100,
|
|
percentage: 78.0,
|
|
benchmark: 80.0,
|
|
status: "below_benchmark",
|
|
},
|
|
eye_exam_screening: {
|
|
numerator: 92,
|
|
denominator: 100,
|
|
percentage: 92.0,
|
|
benchmark: 85.0,
|
|
status: "above_benchmark",
|
|
},
|
|
},
|
|
},
|
|
improvement_opportunities: [
|
|
"Increase HbA1c testing frequency",
|
|
"Improve blood pressure management protocols",
|
|
],
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate safety indicators responses
|
|
*/
|
|
generateSafetyIndicatorsResponse(toolName, parameters) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
safety_indicators: {
|
|
medication_errors: {
|
|
total_incidents: 3,
|
|
severity_breakdown: {
|
|
low: 2,
|
|
moderate: 1,
|
|
high: 0,
|
|
critical: 0,
|
|
},
|
|
error_types: {
|
|
dosing_error: 1,
|
|
wrong_medication: 1,
|
|
timing_error: 1,
|
|
},
|
|
trend: "decreasing",
|
|
},
|
|
adverse_drug_events: {
|
|
total_events: 1,
|
|
preventable: 0,
|
|
severity: "moderate",
|
|
reporting_rate: 100,
|
|
},
|
|
near_miss_events: {
|
|
total_reports: 5,
|
|
categories: ["prescription_clarity", "drug_interaction_alerts"],
|
|
learning_opportunities: 3,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate medical records responses
|
|
*/
|
|
generateMedicalRecordsResponse(toolName, parameters) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
medical_record: {
|
|
id: `record_${Math.random().toString(36).substr(2, 9)}`,
|
|
patient_id:
|
|
parameters.patient_id || parameters.patientId || "patient_123",
|
|
record_type: parameters.record_type || "progress_note",
|
|
created_at: new Date().toISOString(),
|
|
},
|
|
coding_validation: {
|
|
icd10_codes: [
|
|
{
|
|
code: "E11.9",
|
|
description: "Type 2 diabetes mellitus without complications",
|
|
valid: true,
|
|
billable: true,
|
|
specificity: "high",
|
|
},
|
|
],
|
|
coding_accuracy: 100,
|
|
billing_compliance: true,
|
|
},
|
|
cpt_validation: {
|
|
billing_compliance: true,
|
|
codes: [
|
|
{
|
|
code: "99213",
|
|
description: "Office visit, established patient, level 3",
|
|
valid: true,
|
|
modifier_required: false,
|
|
documentation_requirements: [
|
|
"history",
|
|
"examination",
|
|
"medical_decision_making",
|
|
],
|
|
},
|
|
],
|
|
documentation_complete: true,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate task responses
|
|
*/
|
|
generateTaskResponse(toolName, parameters) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
task: {
|
|
id: "task_123",
|
|
patient_id: parameters.patient_id,
|
|
title: parameters.task_title,
|
|
priority: parameters.task_priority,
|
|
assigned_to: parameters.task_assigned_to,
|
|
due_date: parameters.task_due_date,
|
|
status: "pending",
|
|
clinical_flags: ["medication_review", "lab_follow_up"],
|
|
workflow_stage: "review_required",
|
|
},
|
|
workflow_automation: {
|
|
reminders_scheduled: true,
|
|
escalation_rules: "notify_supervisor_if_overdue",
|
|
integration_triggers: ["lab_result_notification"],
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate patient responses
|
|
*/
|
|
generatePatientResponse(toolName, parameters) {
|
|
const patientData = global.testUtils.createMockPatientData();
|
|
|
|
// Override patient data based on parameters for specific test scenarios
|
|
if (parameters.patientId) {
|
|
patientData.id = parameters.patientId;
|
|
}
|
|
|
|
if (parameters.email) {
|
|
patientData.email = parameters.email;
|
|
}
|
|
|
|
if (parameters.lastName) {
|
|
patientData.lastName = parameters.lastName;
|
|
}
|
|
|
|
if (parameters.city) {
|
|
patientData.city = parameters.city;
|
|
}
|
|
|
|
if (parameters.address) {
|
|
patientData.address = parameters.address;
|
|
}
|
|
|
|
const response = {
|
|
success: true,
|
|
data: {
|
|
patient: patientData,
|
|
accessControl: {
|
|
minimumNecessary: true,
|
|
fieldsExcluded: ["personalID", "ssn"],
|
|
userRole: "nurse",
|
|
permissions: ["read:patient_data"],
|
|
restrictions: ["no_billing_access"],
|
|
},
|
|
emergencyAccess: {
|
|
granted: true,
|
|
requiresReview: true,
|
|
auditFlag: "emergency_access",
|
|
},
|
|
consent_verification: {
|
|
consent_obtained: true,
|
|
scope: ["medical_records", "treatment_sharing"],
|
|
tracking_id: "CONSENT_123",
|
|
},
|
|
sharing_details: {
|
|
tracking_id: "SHARE_789",
|
|
},
|
|
deidentification: {
|
|
method: "safe_harbor",
|
|
identifiers_removed: ["name", "address", "phone", "ssn"],
|
|
},
|
|
research_data: [
|
|
{
|
|
patient_id: "DEIDENT_001",
|
|
age_group: "50-60",
|
|
diagnosis: "diabetes",
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
// Add audit trail for HIPAA compliance tests
|
|
if (toolName.includes("getPatientInfo") || toolName.includes("Patient")) {
|
|
response.data.auditTrail = {
|
|
accessId: `audit_${Math.random().toString(36).substr(2, 9)}`,
|
|
accessedBy: "provider_456",
|
|
action: "patient_data_access",
|
|
purpose: "patient_care",
|
|
timestamp: new Date().toISOString(),
|
|
ipAddress: "192.168.1.100",
|
|
userAgent: "Healthcare-MCP-Client/1.0",
|
|
};
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* Generate vital signs responses
|
|
*/
|
|
generateVitalSignsResponse(toolName, parameters) {
|
|
// Validate vital signs ranges
|
|
if (
|
|
parameters.temperature &&
|
|
(parameters.temperature > 110 || parameters.temperature < 95)
|
|
) {
|
|
throw new Error("Invalid temperature: must be between 95°F and 110°F");
|
|
}
|
|
|
|
if (parameters.pulse && (parameters.pulse > 200 || parameters.pulse < 40)) {
|
|
throw new Error("Invalid pulse: must be between 40 and 200 bpm");
|
|
}
|
|
|
|
if (
|
|
parameters.saturation &&
|
|
(parameters.saturation > 100 || parameters.saturation < 70)
|
|
) {
|
|
throw new Error(
|
|
"Invalid oxygen saturation: must be between 70% and 100%"
|
|
);
|
|
}
|
|
|
|
if (
|
|
parameters.heart_rate &&
|
|
(parameters.heart_rate > 200 || parameters.heart_rate < 40)
|
|
) {
|
|
throw new Error("Invalid heart rate: must be between 40 and 200 bpm");
|
|
}
|
|
|
|
if (
|
|
parameters.respiratory_rate &&
|
|
(parameters.respiratory_rate > 40 || parameters.respiratory_rate < 8)
|
|
) {
|
|
throw new Error(
|
|
"Invalid respiratory rate: must be between 8 and 40 breaths per minute"
|
|
);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
vital_signs: {
|
|
id: `vital_${Math.random().toString(36).substr(2, 9)}`,
|
|
patientId: parameters.patientId,
|
|
providerId: parameters.provider_id,
|
|
bloodPressure: parameters.blood_presssure || "120/80",
|
|
heartRate: parameters.heart_rate || 72,
|
|
temperature: parameters.temperature || 98.6,
|
|
respiratoryRate: parameters.respiratory_rate || 16,
|
|
oxygenSaturation: parameters.oxygen_saturation || 98,
|
|
weight: parameters.weight || 150,
|
|
height: parameters.height || 68,
|
|
bmi: parameters.bmi || 22.8,
|
|
recordedAt: new Date().toISOString(),
|
|
recordedBy: parameters.provider_id || "provider_456",
|
|
},
|
|
validation: {
|
|
allWithinNormalRange: true,
|
|
alerts: [],
|
|
recommendations: [],
|
|
},
|
|
auditTrail: {
|
|
accessId: `audit_${Math.random().toString(36).substr(2, 9)}`,
|
|
userId: parameters.provider_id || "provider_456",
|
|
action: "vital_signs_recorded",
|
|
timestamp: new Date().toISOString(),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate password responses
|
|
*/
|
|
generatePasswordResponse(toolName, parameters) {
|
|
if (toolName.includes("forgot")) {
|
|
// Customize message based on specific tool
|
|
let message = "Password reset email sent successfully";
|
|
if (toolName.includes("frontend")) {
|
|
message = "Patient password reset email sent successfully";
|
|
} else if (toolName.includes("provider")) {
|
|
message = "Provider password reset email sent successfully";
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
message: message,
|
|
reset_token_sent: true,
|
|
email: parameters.email,
|
|
},
|
|
};
|
|
}
|
|
|
|
if (toolName.includes("reset") || toolName.includes("Reset")) {
|
|
// Customize message for different reset types
|
|
let message = "Password reset successfully";
|
|
if (toolName.includes("frontend")) {
|
|
message = "Patient password reset successfully";
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
message: message,
|
|
password_updated: true,
|
|
security_requirements_met: true,
|
|
},
|
|
};
|
|
}
|
|
|
|
if (
|
|
toolName.includes("set") &&
|
|
!toolName.includes("reset") &&
|
|
!toolName.includes("Reset")
|
|
) {
|
|
// Customize message for different set operations
|
|
let message = "Password set successfully";
|
|
if (toolName.includes("emr")) {
|
|
message = "EMR password set successfully";
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
message: message,
|
|
password_updated: true,
|
|
security_requirements_met: true,
|
|
},
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
message: "Password operation completed",
|
|
parameters: parameters,
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate medicine template responses
|
|
*/
|
|
generateMedicineTemplateResponse(toolName, parameters) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
template: {
|
|
id: `template_${Math.random().toString(36).substr(2, 9)}`,
|
|
templateName:
|
|
parameters.template_data?.template_name || "Default Template",
|
|
medicationName:
|
|
parameters.template_data?.medication_name || "Lisinopril",
|
|
strength: parameters.template_data?.strength || "10mg",
|
|
dosage: parameters.template_data?.dosage || "10mg daily",
|
|
frequency: parameters.template_data?.frequency || "Once daily",
|
|
instructions:
|
|
parameters.template_data?.instructions || "Take with food",
|
|
created_at: new Date().toISOString(),
|
|
},
|
|
auditTrail: {
|
|
accessId: `audit_${Math.random().toString(36).substr(2, 9)}`,
|
|
userId: "provider_456",
|
|
action: "template_created",
|
|
timestamp: new Date().toISOString(),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate appointment participant responses
|
|
*/
|
|
generateAppointmentParticipantResponse(toolName, parameters) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
participants: [
|
|
{
|
|
id: "participant_1",
|
|
role: "provider",
|
|
name: "Dr. Smith",
|
|
email: "dr.smith@healthcare.com",
|
|
},
|
|
{
|
|
id: "participant_2",
|
|
role: "patient",
|
|
name: "John Doe",
|
|
email: "john.doe@email.com",
|
|
},
|
|
],
|
|
appointmentId: parameters.appointmentId || "appointment_123",
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate available slots responses
|
|
*/
|
|
generateAvailableSlotsResponse(toolName, parameters) {
|
|
// Handle no available slots scenario
|
|
if (parameters.date === "2025-08-01") {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
availableSlots: [],
|
|
date: parameters.date,
|
|
},
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
availableSlots: [
|
|
{
|
|
time: "09:00",
|
|
duration: 30,
|
|
provider: "Dr. Smith",
|
|
},
|
|
{
|
|
time: "10:30",
|
|
duration: 30,
|
|
provider: "Dr. Johnson",
|
|
},
|
|
{
|
|
time: "14:00",
|
|
duration: 30,
|
|
provider: "Dr. Brown",
|
|
},
|
|
],
|
|
date: parameters.date,
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate book appointment responses
|
|
*/
|
|
generateBookAppointmentResponse(toolName, parameters) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
appointment: {
|
|
id: `appointment_${Math.random().toString(36).substr(2, 9)}`,
|
|
status: "scheduled",
|
|
date: parameters.date,
|
|
time: parameters.time,
|
|
patient_id: parameters.patient_id,
|
|
provider_id: parameters.provider_id || "provider_123",
|
|
type: parameters.appointment_type || "consultation",
|
|
},
|
|
confirmation: {
|
|
confirmation_number: `CONF_${Math.random()
|
|
.toString(36)
|
|
.substr(2, 8)
|
|
.toUpperCase()}`,
|
|
created_at: new Date().toISOString(),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate login responses
|
|
*/
|
|
generateLoginResponse(toolName, parameters) {
|
|
// Record the request in HTTP history (with password redacted for security)
|
|
const sanitizedParams = { ...parameters };
|
|
if (sanitizedParams.password) {
|
|
sanitizedParams.password = "[REDACTED]";
|
|
}
|
|
|
|
// Record the request
|
|
this.httpMocks.requestHistory.push({
|
|
method: "POST",
|
|
url: "/api/login",
|
|
data: sanitizedParams,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
|
|
// Determine login type and generate appropriate response
|
|
if (toolName.includes("frontend")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
user: {
|
|
id: "patient_123",
|
|
email: parameters.email || parameters.username,
|
|
role: "patient",
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
},
|
|
token: "patient_token_abc123",
|
|
expires_in: 3600,
|
|
portal_access: true,
|
|
},
|
|
};
|
|
}
|
|
|
|
if (toolName.includes("admin")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
user: {
|
|
id: "admin_456",
|
|
email: parameters.email || parameters.username,
|
|
role: "admin",
|
|
firstName: "Admin",
|
|
lastName: "User",
|
|
},
|
|
token: "admin_token_def456",
|
|
expires_in: 3600,
|
|
permissions: ["all"],
|
|
},
|
|
};
|
|
}
|
|
|
|
if (toolName.includes("Partner") || toolName.includes("partner")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
user: {
|
|
id: "partner_789",
|
|
email: parameters.email || parameters.username,
|
|
role: "partner",
|
|
company: "Partner Healthcare",
|
|
},
|
|
token: "partner_token_ghi789",
|
|
expires_in: 3600,
|
|
api_access: true,
|
|
},
|
|
};
|
|
}
|
|
|
|
if (toolName.includes("affiliate")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
user: {
|
|
id: "affiliate_101",
|
|
email: parameters.email || parameters.username,
|
|
role: "affiliate",
|
|
organization: "Affiliate Network",
|
|
},
|
|
token: "affiliate_token_jkl101",
|
|
expires_in: 3600,
|
|
network_access: true,
|
|
},
|
|
};
|
|
}
|
|
|
|
if (toolName.includes("network")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
user: {
|
|
id: "network_202",
|
|
email: parameters.email || parameters.username,
|
|
role: "network",
|
|
network_id: "net_001",
|
|
},
|
|
token: "network_token_mno202",
|
|
expires_in: 3600,
|
|
network_permissions: ["read", "write"],
|
|
},
|
|
};
|
|
}
|
|
|
|
// Default provider/general login
|
|
return {
|
|
success: true,
|
|
data: {
|
|
user: {
|
|
id: "provider_456",
|
|
email: parameters.email || parameters.username,
|
|
role: "provider",
|
|
firstName: "Dr.",
|
|
lastName: "Smith",
|
|
},
|
|
token: "provider_token_pqr456",
|
|
expires_in: 3600,
|
|
provider_access: true,
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate registration responses
|
|
*/
|
|
generateRegistrationResponse(toolName, parameters) {
|
|
// Record the request in HTTP history (with password redacted for security)
|
|
const sanitizedParams = { ...parameters };
|
|
if (sanitizedParams.password) {
|
|
sanitizedParams.password = "[REDACTED]";
|
|
}
|
|
if (sanitizedParams.newUserPassword) {
|
|
sanitizedParams.newUserPassword = "[REDACTED]";
|
|
}
|
|
|
|
// Record the request
|
|
this.httpMocks.requestHistory.push({
|
|
method: "POST",
|
|
url: "/api/register",
|
|
data: sanitizedParams,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
|
|
// Provider registration
|
|
if (toolName.includes("provider") || toolName.includes("Provider")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
provider: {
|
|
id: "provider_123",
|
|
firstName: parameters.firstName || "Dr. John",
|
|
lastName: parameters.lastName || "Smith",
|
|
username: parameters.username || "drsmith",
|
|
emailAddress:
|
|
parameters.emailAddress ||
|
|
parameters.email ||
|
|
"dr.smith@test.com",
|
|
textMessageNumber: parameters.textMessageNumber || "555-0123",
|
|
company_name: parameters.company_name || "Test Medical Center",
|
|
status: "active",
|
|
role: "provider",
|
|
},
|
|
message: "Provider registered successfully",
|
|
registration_id: "reg_provider_123",
|
|
},
|
|
};
|
|
}
|
|
|
|
// Patient registration
|
|
if (toolName.includes("patient") || toolName.includes("Patient")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
patient: {
|
|
id: "patient_456",
|
|
firstName: parameters.firstName || parameters.first_name || "John",
|
|
lastName: parameters.lastName || parameters.last_name || "Doe",
|
|
email: parameters.email || "john.doe@test.com",
|
|
dateOfBirth:
|
|
parameters.dateOfBirth || parameters.dob || "1990-01-01",
|
|
phone: parameters.phone || parameters.phone_no || "555-0123",
|
|
status: "active",
|
|
role: "patient",
|
|
},
|
|
message: "Patient registered successfully",
|
|
registration_id: "reg_patient_456",
|
|
},
|
|
};
|
|
}
|
|
|
|
// Affiliate registration
|
|
if (toolName.includes("affiliate") || toolName.includes("Affiliate")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
affiliate: {
|
|
id: "affiliate_789",
|
|
first_name: parameters.first_name || "Alice",
|
|
last_name: parameters.last_name || "Johnson",
|
|
email: parameters.email || "alice.johnson@test.com",
|
|
phone: parameters.phone || "555-0456",
|
|
status: "active",
|
|
role: "affiliate",
|
|
},
|
|
message: "Affiliate registered successfully",
|
|
registration_id: "reg_affiliate_789",
|
|
},
|
|
};
|
|
}
|
|
|
|
// Partner registration
|
|
if (toolName.includes("partner") || toolName.includes("Partner")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
partner: {
|
|
id: "partner_101",
|
|
first_name: parameters.first_name || "Bob",
|
|
last_name: parameters.last_name || "Wilson",
|
|
email: parameters.email || "bob.wilson@test.com",
|
|
phone: parameters.phone || "555-0789",
|
|
status: "active",
|
|
role: "partner",
|
|
},
|
|
message: "Partner registered successfully",
|
|
registration_id: "reg_partner_101",
|
|
},
|
|
};
|
|
}
|
|
|
|
// Network registration
|
|
if (toolName.includes("network") || toolName.includes("Network")) {
|
|
return {
|
|
success: true,
|
|
data: {
|
|
network_user: {
|
|
id: "network_202",
|
|
first_name: parameters.first_name || "Carol",
|
|
last_name: parameters.last_name || "Davis",
|
|
email: parameters.email || "carol.davis@test.com",
|
|
phone: parameters.phone || "555-0321",
|
|
status: "active",
|
|
role: "network",
|
|
},
|
|
message: "Network user registered successfully",
|
|
registration_id: "reg_network_202",
|
|
},
|
|
};
|
|
}
|
|
|
|
// Default registration response
|
|
return {
|
|
success: true,
|
|
data: {
|
|
user: {
|
|
id: "user_999",
|
|
firstName: parameters.firstName || parameters.first_name || "Default",
|
|
lastName: parameters.lastName || parameters.last_name || "User",
|
|
email:
|
|
parameters.email || parameters.emailAddress || "default@test.com",
|
|
status: "active",
|
|
role: "user",
|
|
},
|
|
message: "User registered successfully",
|
|
registration_id: "reg_user_999",
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Reset all mocks to initial state
|
|
*/
|
|
resetAllMocks() {
|
|
this.httpMocks.reset();
|
|
this.authMocks.reset();
|
|
this.healthcareMocks.reset();
|
|
this.componentMocks.clear();
|
|
jest.clearAllMocks();
|
|
}
|
|
|
|
/**
|
|
* Get comprehensive test statistics
|
|
* @returns {Object} Test statistics
|
|
*/
|
|
getTestStatistics() {
|
|
return {
|
|
httpRequests: this.httpMocks.getRequestHistory().length,
|
|
authEvents: this.authMocks.getAuthHistory().length,
|
|
mockCalls: jest.getMockImplementationDetails
|
|
? "Available"
|
|
: "Not available",
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate a comprehensive list of mock tools for testing
|
|
* @returns {Array} Array of mock tool definitions
|
|
*/
|
|
generateMockToolsList() {
|
|
const tools = [];
|
|
|
|
// Public tools (77 tools expected)
|
|
const publicTools = [
|
|
// Login tools
|
|
"public_create_login",
|
|
"public_create_frontendlogin",
|
|
"public_create_adminlogin",
|
|
"public_create_loginPartnerApi",
|
|
"public_create_affiliateLoginApi",
|
|
"public_create_networklogin",
|
|
"public_create_doctorlogin",
|
|
"public_create_practitionerlogin",
|
|
|
|
// Registration tools
|
|
"public_create_register",
|
|
"public_create_frontendregister",
|
|
"public_create_adminregister",
|
|
"public_create_partnerregister",
|
|
"public_create_affiliateregister",
|
|
"public_create_networkregister",
|
|
"public_create_doctorregister",
|
|
"public_create_practitionerregister",
|
|
"public_create_patientregister",
|
|
"public_create_providerregister",
|
|
|
|
// Password management tools
|
|
"public_create_forgotPassword",
|
|
"public_create_frontendforgotPassword",
|
|
"public_create_providerforgotPassword",
|
|
"public_create_passwordReset",
|
|
"public_create_frontendresetPassword",
|
|
"public_create_setPassword",
|
|
"public_create_emrsetPassword",
|
|
"public_create_changePassword",
|
|
"public_create_updatePassword",
|
|
"public_create_resetUserPassword",
|
|
|
|
// Verification tools
|
|
"public_create_verifyEmail",
|
|
"public_create_resendVerification",
|
|
"public_create_verifyAccount",
|
|
"public_create_confirmEmail",
|
|
"public_create_activateAccount",
|
|
|
|
// Public data access tools
|
|
"public_get_publicData",
|
|
"public_get_healthcareProviders",
|
|
"public_get_medicalSpecialties",
|
|
"public_get_insuranceProviders",
|
|
"public_get_pharmacies",
|
|
"public_get_laboratories",
|
|
"public_get_hospitalNetworks",
|
|
"public_get_clinicLocations",
|
|
"public_get_emergencyContacts",
|
|
"public_get_healthcareNews",
|
|
"public_get_medicalEducation",
|
|
"public_get_preventiveCare",
|
|
"public_get_healthScreenings",
|
|
"public_get_vaccinationInfo",
|
|
"public_get_healthTips",
|
|
"public_get_nutritionGuidance",
|
|
"public_get_exercisePrograms",
|
|
"public_get_mentalHealthResources",
|
|
"public_get_substanceAbuseHelp",
|
|
"public_get_elderCareServices",
|
|
"public_get_pediatricCare",
|
|
"public_get_womensHealth",
|
|
"public_get_mensHealth",
|
|
"public_get_chronicDiseaseManagement",
|
|
"public_get_medicationInformation",
|
|
"public_get_drugInteractions",
|
|
"public_get_allergyInformation",
|
|
"public_get_symptomChecker",
|
|
"public_get_firstAidGuide",
|
|
"public_get_emergencyProcedures",
|
|
"public_get_healthcareRights",
|
|
"public_get_patientAdvocacy",
|
|
"public_get_insuranceGuidance",
|
|
"public_get_billingInformation",
|
|
"public_get_paymentOptions",
|
|
"public_get_financialAssistance",
|
|
"public_get_healthcareCosts",
|
|
"public_get_qualityRatings",
|
|
"public_get_patientReviews",
|
|
"public_get_providerCredentials",
|
|
"public_get_facilityAccreditation",
|
|
"public_get_complianceReports",
|
|
"public_get_safetyRecords",
|
|
"public_get_outcomeStatistics",
|
|
"public_get_performanceMetrics",
|
|
"public_get_patientSatisfaction",
|
|
];
|
|
|
|
// Generate public tool definitions
|
|
publicTools.forEach((toolName) => {
|
|
tools.push({
|
|
name: toolName,
|
|
description: `Public: ${toolName
|
|
.replace("public_", "")
|
|
.replace("_", " ")}`,
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
// Basic properties that most tools would have
|
|
...(toolName.includes("login") && {
|
|
username: { type: "string" },
|
|
password: { type: "string" },
|
|
}),
|
|
...(toolName.includes("register") && {
|
|
firstName: { type: "string" },
|
|
lastName: { type: "string" },
|
|
email: { type: "string" },
|
|
password: { type: "string" },
|
|
}),
|
|
...(toolName.includes("password") && {
|
|
email: { type: "string" },
|
|
token: { type: "string" },
|
|
newPassword: { type: "string" },
|
|
}),
|
|
},
|
|
required: toolName.includes("login")
|
|
? ["username", "password"]
|
|
: toolName.includes("register")
|
|
? ["firstName", "lastName", "email", "password"]
|
|
: toolName.includes("password")
|
|
? ["email"]
|
|
: [],
|
|
},
|
|
});
|
|
});
|
|
|
|
// Add some provider tools
|
|
const providerTools = [
|
|
"provider_create_emrregisterPatient",
|
|
"provider_create_emrupdatePatient",
|
|
"provider_create_prescriptionstore",
|
|
"provider_create_add_medicine_template",
|
|
"provider_create_emrimportMedicine",
|
|
"provider_create_medicalRecordscreate",
|
|
"provider_create_addVital",
|
|
"provider_create_getPatientInfo",
|
|
"provider_create_updatePatientInfo",
|
|
];
|
|
|
|
providerTools.forEach((toolName) => {
|
|
tools.push({
|
|
name: toolName,
|
|
description: `Provider: ${toolName
|
|
.replace("provider_", "")
|
|
.replace("_", " ")}`,
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
patient_id: { type: "string" },
|
|
provider_id: { type: "string" },
|
|
},
|
|
required: ["patient_id"],
|
|
},
|
|
});
|
|
});
|
|
|
|
// Add some patient tools
|
|
const patientTools = [
|
|
"patient_get_medicalRecords",
|
|
"patient_get_prescriptions",
|
|
"patient_get_appointments",
|
|
"patient_post_scheduleAppointment",
|
|
"patient_put_updatePatientProfile",
|
|
"patient_put_cancelAppointment",
|
|
];
|
|
|
|
patientTools.forEach((toolName) => {
|
|
tools.push({
|
|
name: toolName,
|
|
description: `Patient: ${toolName
|
|
.replace("patient_", "")
|
|
.replace("_", " ")}`,
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
patient_id: { type: "string" },
|
|
},
|
|
required: ["patient_id"],
|
|
},
|
|
});
|
|
});
|
|
|
|
return tools;
|
|
}
|
|
}
|
|
|
|
// Export singleton instance
|
|
export const mockFactory = new MockFactory();
|