use redis_enterprise::ldap_mappings::LdapMappingHandler;
use redis_enterprise::redis_acls::{CreateRedisAclRequest, RedisAclHandler};
use redis_enterprise::roles::{CreateRoleRequest, RolesHandler};
use redis_enterprise::users::{CreateUserRequest, UpdateUserRequest, UserHandler};
use serde_json::Value;
use tower_mcp::{CallToolResult, ResultExt};
use crate::tools::macros::{enterprise_tool, mcp_module};
mcp_module! {
list_users => "list_enterprise_users",
get_user => "get_enterprise_user",
create_enterprise_user => "create_enterprise_user",
update_enterprise_user => "update_enterprise_user",
delete_enterprise_user => "delete_enterprise_user",
get_enterprise_user_permissions => "get_enterprise_user_permissions",
list_roles => "list_enterprise_roles",
get_role => "get_enterprise_role",
create_enterprise_role => "create_enterprise_role",
update_enterprise_role => "update_enterprise_role",
delete_enterprise_role => "delete_enterprise_role",
get_enterprise_builtin_roles => "get_enterprise_builtin_roles",
list_redis_acls => "list_enterprise_acls",
get_redis_acl => "get_enterprise_acl",
create_enterprise_acl => "create_enterprise_acl",
update_enterprise_acl => "update_enterprise_acl",
delete_enterprise_acl => "delete_enterprise_acl",
validate_enterprise_acl => "validate_enterprise_acl",
get_enterprise_ldap_config => "get_enterprise_ldap_config",
update_enterprise_ldap_config => "update_enterprise_ldap_config",
}
enterprise_tool!(read_only, list_users, "list_enterprise_users",
"List all users.",
{} => |client, _input| {
let handler = UserHandler::new(client);
let users = handler.list().await.tool_context("Failed to list users")?;
CallToolResult::from_list("users", &users)
}
);
enterprise_tool!(read_only, get_user, "get_enterprise_user",
"Get user details by UID.",
{
pub uid: u32,
} => |client, input| {
let handler = UserHandler::new(client);
let user = handler
.get(input.uid)
.await
.tool_context("Failed to get user")?;
CallToolResult::from_serialize(&user)
}
);
enterprise_tool!(write, create_enterprise_user, "create_enterprise_user",
"Create a new user. \
Prerequisites: 1) list_enterprise_roles -- identify roles to assign. \
2) list_enterprise_users -- check for existing users to avoid duplicates.",
{
pub email: String,
pub password: String,
pub role: String,
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
pub email_alerts: Option<bool>,
#[serde(default)]
pub role_uids: Option<Vec<u32>>,
} => |client, input| {
let request = CreateUserRequest {
email: input.email,
password: input.password,
role: input.role,
name: input.name,
email_alerts: input.email_alerts,
bdbs_email_alerts: None,
role_uids: input.role_uids,
auth_method: None,
};
let handler = UserHandler::new(client);
let user = handler
.create(request)
.await
.tool_context("Failed to create user")?;
CallToolResult::from_serialize(&user)
}
);
enterprise_tool!(write, update_enterprise_user, "update_enterprise_user",
"Update an existing user. Only specified fields will be modified.",
{
pub uid: u32,
#[serde(default)]
pub password: Option<String>,
#[serde(default)]
pub role: Option<String>,
#[serde(default)]
pub email: Option<String>,
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
pub email_alerts: Option<bool>,
#[serde(default)]
pub role_uids: Option<Vec<u32>>,
} => |client, input| {
let request = UpdateUserRequest {
password: input.password,
role: input.role,
email: input.email,
name: input.name,
email_alerts: input.email_alerts,
bdbs_email_alerts: None,
role_uids: input.role_uids,
auth_method: None,
};
let handler = UserHandler::new(client);
let user = handler
.update(input.uid, request)
.await
.tool_context("Failed to update user")?;
CallToolResult::from_serialize(&user)
}
);
enterprise_tool!(destructive, delete_enterprise_user, "delete_enterprise_user",
"DANGEROUS: Delete a user. Active sessions will be terminated.",
{
pub uid: u32,
} => |client, input| {
let handler = UserHandler::new(client);
handler
.delete(input.uid)
.await
.tool_context("Failed to delete user")?;
CallToolResult::from_serialize(&serde_json::json!({
"message": "User deleted successfully",
"uid": input.uid
}))
}
);
enterprise_tool!(read_only, get_enterprise_user_permissions, "get_enterprise_user_permissions",
"Get all available permission types for user management.",
{} => |client, _input| {
let handler = UserHandler::new(client);
let permissions = handler
.permissions()
.await
.tool_context("Failed to get user permissions")?;
CallToolResult::from_serialize(&permissions)
}
);
enterprise_tool!(read_only, list_roles, "list_enterprise_roles",
"List all roles.",
{} => |client, _input| {
let handler = RolesHandler::new(client);
let roles = handler.list().await.tool_context("Failed to list roles")?;
CallToolResult::from_list("roles", &roles)
}
);
enterprise_tool!(read_only, get_role, "get_enterprise_role",
"Get role details by UID, including permissions and assignments.",
{
pub uid: u32,
} => |client, input| {
let handler = RolesHandler::new(client);
let role = handler
.get(input.uid)
.await
.tool_context("Failed to get role")?;
CallToolResult::from_serialize(&role)
}
);
enterprise_tool!(write, create_enterprise_role, "create_enterprise_role",
"Create a new role. \
Prerequisites: 1) get_enterprise_builtin_roles -- review built-in roles before creating custom ones. \
2) list_enterprise_acls -- identify Redis ACLs to attach to the role.",
{
pub name: String,
#[serde(default)]
pub management: Option<String>,
#[serde(default)]
pub data_access: Option<String>,
} => |client, input| {
let request = CreateRoleRequest {
name: input.name,
management: input.management,
data_access: input.data_access,
bdb_roles: None,
cluster_roles: None,
};
let handler = RolesHandler::new(client);
let role = handler
.create(request)
.await
.tool_context("Failed to create role")?;
CallToolResult::from_serialize(&role)
}
);
enterprise_tool!(write, update_enterprise_role, "update_enterprise_role",
"Update an existing role.",
{
pub uid: u32,
pub name: String,
#[serde(default)]
pub management: Option<String>,
#[serde(default)]
pub data_access: Option<String>,
} => |client, input| {
let request = CreateRoleRequest {
name: input.name,
management: input.management,
data_access: input.data_access,
bdb_roles: None,
cluster_roles: None,
};
let handler = RolesHandler::new(client);
let role = handler
.update(input.uid, request)
.await
.tool_context("Failed to update role")?;
CallToolResult::from_serialize(&role)
}
);
enterprise_tool!(destructive, delete_enterprise_role, "delete_enterprise_role",
"DANGEROUS: Delete a role. Users assigned to it will lose their permissions.",
{
pub uid: u32,
} => |client, input| {
let handler = RolesHandler::new(client);
handler
.delete(input.uid)
.await
.tool_context("Failed to delete role")?;
CallToolResult::from_serialize(&serde_json::json!({
"message": "Role deleted successfully",
"uid": input.uid
}))
}
);
enterprise_tool!(read_only, get_enterprise_builtin_roles, "get_enterprise_builtin_roles",
"Get the list of built-in roles.",
{} => |client, _input| {
let handler = RolesHandler::new(client);
let roles = handler
.built_in()
.await
.tool_context("Failed to get built-in roles")?;
CallToolResult::from_list("roles", &roles)
}
);
enterprise_tool!(read_only, list_redis_acls, "list_enterprise_acls",
"List all Redis ACLs.",
{} => |client, _input| {
let handler = RedisAclHandler::new(client);
let acls = handler.list().await.tool_context("Failed to list ACLs")?;
CallToolResult::from_list("acls", &acls)
}
);
enterprise_tool!(read_only, get_redis_acl, "get_enterprise_acl",
"Get Redis ACL details by UID, including rule string and associated databases.",
{
pub uid: u32,
} => |client, input| {
let handler = RedisAclHandler::new(client);
let acl = handler
.get(input.uid)
.await
.tool_context("Failed to get ACL")?;
CallToolResult::from_serialize(&acl)
}
);
enterprise_tool!(write, create_enterprise_acl, "create_enterprise_acl",
"Create a new Redis ACL using Redis ACL syntax (e.g., \"+@all ~*\"). \
Prerequisites: 1) list_enterprise_acls -- review existing ACLs to avoid duplicates. \
2) validate_enterprise_acl -- validate ACL syntax before creation.",
{
pub name: String,
pub acl: String,
#[serde(default)]
pub description: Option<String>,
} => |client, input| {
let request = CreateRedisAclRequest {
name: input.name,
acl: input.acl,
description: input.description,
};
let handler = RedisAclHandler::new(client);
let acl = handler
.create(request)
.await
.tool_context("Failed to create ACL")?;
CallToolResult::from_serialize(&acl)
}
);
enterprise_tool!(write, update_enterprise_acl, "update_enterprise_acl",
"Update an existing Redis ACL.",
{
pub uid: u32,
pub name: String,
pub acl: String,
#[serde(default)]
pub description: Option<String>,
} => |client, input| {
let request = CreateRedisAclRequest {
name: input.name,
acl: input.acl,
description: input.description,
};
let handler = RedisAclHandler::new(client);
let acl = handler
.update(input.uid, request)
.await
.tool_context("Failed to update ACL")?;
CallToolResult::from_serialize(&acl)
}
);
enterprise_tool!(destructive, delete_enterprise_acl, "delete_enterprise_acl",
"DANGEROUS: Delete a Redis ACL. Databases using it will lose those access controls.",
{
pub uid: u32,
} => |client, input| {
let handler = RedisAclHandler::new(client);
handler
.delete(input.uid)
.await
.tool_context("Failed to delete ACL")?;
CallToolResult::from_serialize(&serde_json::json!({
"message": "ACL deleted successfully",
"uid": input.uid
}))
}
);
enterprise_tool!(read_only, validate_enterprise_acl, "validate_enterprise_acl",
"Validate a Redis ACL rule before creating it.",
{
pub name: String,
pub acl: String,
#[serde(default)]
pub description: Option<String>,
} => |client, input| {
let request = CreateRedisAclRequest {
name: input.name,
acl: input.acl,
description: input.description,
};
let handler = RedisAclHandler::new(client);
let result = handler
.validate(request)
.await
.tool_context("Failed to validate ACL")?;
CallToolResult::from_serialize(&result)
}
);
enterprise_tool!(read_only, get_enterprise_ldap_config, "get_enterprise_ldap_config",
"Get the LDAP configuration including server settings, bind DN, and query suffixes.",
{} => |client, _input| {
let handler = LdapMappingHandler::new(client);
let config = handler
.get_config()
.await
.tool_context("Failed to get LDAP config")?;
CallToolResult::from_serialize(&config)
}
);
enterprise_tool!(write, update_enterprise_ldap_config, "update_enterprise_ldap_config",
"Update the LDAP configuration. Pass LDAP settings as JSON.",
{
pub config: Value,
} => |client, input| {
let config = serde_json::from_value(input.config)
.tool_context("Invalid LDAP config")?;
let handler = LdapMappingHandler::new(client);
let result = handler
.update_config(config)
.await
.tool_context("Failed to update LDAP config")?;
CallToolResult::from_serialize(&result)
}
);