okta-mcp-server
Version:
Model Context Protocol (MCP) server for Okta API operations with support for bulk operations and caching
136 lines • 4.5 kB
JavaScript
/**
* Read-Only Mode Middleware
*
* Prevents dangerous write operations when READ_ONLY_MODE is enabled.
* This is crucial for production environments where data modification
* should be restricted.
*/
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import { protocolSafeLogger as logger } from '../../utils/protocol-safe-logger.js';
// Define write operations that should be blocked in read-only mode
const WRITE_OPERATIONS = new Set([
// User operations
'createUser',
'updateUser',
'deleteUser',
// Group operations
'createGroup',
'updateGroup',
'deleteGroup',
'addGroupMember',
'removeGroupMember',
// Application operations
'createApp',
'updateApp',
'deleteApp',
'activateApp',
'deactivateApp',
'assignUserToApp',
'assignGroupToApp',
'removeUserFromApp',
'removeGroupFromApp',
'updateAppUser',
// Policy operations
'createPasswordPolicy',
'createSignOnPolicy',
'createMfaPolicy',
'updatePolicy',
'deletePolicy',
'activatePolicy',
'deactivatePolicy',
'createPolicyRule',
'updatePolicyRule',
'deletePolicyRule',
'activatePolicyRule',
'deactivatePolicyRule',
// Bulk operations
'bulkCreateUsers',
'bulkUpdateUsers',
'bulkDeleteUsers',
]);
// Define read-only operations that are allowed
const READ_OPERATIONS = new Set([
// User operations
'listUsers',
'getUser',
'getUserGroups',
// Group operations
'listGroups',
'getGroup',
'listGroupMembers',
// Application operations
'listApps',
'getApp',
'listAppUsers',
'listAppGroups',
// Policy operations
'listPolicies',
'getPolicy',
'listPolicyRules',
'getPolicyRule',
// Audit operations (all are read-only)
'queryAuditLogs',
'getAuditStatistics',
'exportAuditLogs',
'checkAuditIntegrity',
'generateComplianceReport',
'getAuditMetrics',
// Export operations (read-only)
'exportUsers',
'generateImportTemplate',
'getBulkOperationStatus',
]);
export class ReadOnlyMiddleware {
readOnlyMode;
constructor(config) {
this.readOnlyMode = config.features?.readOnlyMode ?? false;
if (this.readOnlyMode) {
logger.warn('🔒 READ-ONLY MODE ENABLED: Write operations are disabled for safety');
}
}
/**
* Check if an operation is allowed in read-only mode
*/
checkOperation(toolName) {
if (!this.readOnlyMode) {
return; // Not in read-only mode, allow all operations
}
// Check if this is a write operation
if (WRITE_OPERATIONS.has(toolName)) {
logger.error(`🚫 Blocked write operation in read-only mode: ${toolName}`);
throw new McpError(ErrorCode.InvalidRequest, `Write operation '${toolName}' is not allowed in read-only mode. ` +
`This server is configured for read-only access to prevent accidental data modification. ` +
`To enable write operations, set READ_ONLY_MODE=false in your environment variables.`);
}
// Verify it's a known read operation
if (!READ_OPERATIONS.has(toolName)) {
logger.warn(`⚠️ Unknown operation in read-only mode: ${toolName}`);
// Allow unknown operations by default, but log them
}
logger.debug(`✅ Allowed read operation: ${toolName}`);
}
/**
* Get information about read-only mode status
*/
getStatus() {
return {
readOnlyMode: this.readOnlyMode,
allowedOperations: Array.from(READ_OPERATIONS).sort(),
blockedOperations: Array.from(WRITE_OPERATIONS).sort(),
};
}
/**
* Get a user-friendly message about read-only mode
*/
getReadOnlyMessage() {
if (!this.readOnlyMode) {
return 'Read-only mode is disabled. All operations are allowed.';
}
return (`🔒 This Okta MCP Server is running in READ-ONLY MODE for safety.\n\n` +
`✅ Allowed operations: Data queries, exports, and audit operations\n` +
`🚫 Blocked operations: Creating, updating, or deleting users, groups, apps, and policies\n\n` +
`This prevents accidental data modification in production environments.\n` +
`To enable write operations, set READ_ONLY_MODE=false in your environment variables.`);
}
}
//# sourceMappingURL=read-only-middleware.js.map