use crate::{
ResourceProvider,
mcp_integration::core::{ScimMcpServer, ScimToolResult},
multi_tenant::TenantContext,
operation_handler::ScimOperationRequest,
resource::version::ScimVersion,
};
use serde_json::{Value, json};
pub async fn handle_create_user<P: ResourceProvider + Send + Sync + 'static>(
server: &ScimMcpServer<P>,
arguments: Value,
) -> ScimToolResult {
let user_data = match arguments.get("user_data") {
Some(data) => data.clone(),
None => {
return ScimToolResult {
success: false,
content: json!({"error": "Missing user_data parameter"}),
metadata: None,
};
}
};
let tenant_context = arguments
.get("tenant_id")
.and_then(|t| t.as_str())
.map(|id| TenantContext::new(id.to_string(), "mcp-client".to_string()));
let mut request = ScimOperationRequest::create("User".to_string(), user_data);
if let Some(tenant) = tenant_context {
request = request.with_tenant(tenant);
}
let response = server.operation_handler.handle_operation(request).await;
if response.success {
let mut content = response
.data
.unwrap_or_else(|| json!({"status": "created"}));
let mut metadata = json!({
"operation": "create_user",
"resource_type": "User",
"resource_id": response.metadata.resource_id
});
if let Some(version) = response.metadata.additional.get("version") {
metadata["version"] = version.clone();
if let Some(content_obj) = content.as_object_mut() {
content_obj.insert("_version".to_string(), version.clone());
}
}
ScimToolResult {
success: true,
content,
metadata: Some(metadata),
}
} else {
ScimToolResult {
success: false,
content: json!({
"error": response.error.unwrap_or_else(|| "Create failed".to_string()),
"error_code": "CREATE_USER_FAILED"
}),
metadata: None,
}
}
}
pub async fn handle_get_user<P: ResourceProvider + Send + Sync + 'static>(
server: &ScimMcpServer<P>,
arguments: Value,
) -> ScimToolResult {
let user_id = match arguments.get("user_id").and_then(|id| id.as_str()) {
Some(id) => id,
None => {
return ScimToolResult {
success: false,
content: json!({"error": "Missing user_id parameter"}),
metadata: None,
};
}
};
let tenant_context = arguments
.get("tenant_id")
.and_then(|t| t.as_str())
.map(|id| TenantContext::new(id.to_string(), "mcp-client".to_string()));
let mut request = ScimOperationRequest::get("User".to_string(), user_id.to_string());
if let Some(tenant) = tenant_context {
request = request.with_tenant(tenant);
}
let response = server.operation_handler.handle_operation(request).await;
if response.success {
let mut content = response
.data
.unwrap_or_else(|| json!({"status": "retrieved"}));
let mut metadata = json!({
"operation": "get_user",
"resource_type": "User",
"resource_id": user_id
});
if let Some(version) = response.metadata.additional.get("version") {
metadata["version"] = version.clone();
if let Some(content_obj) = content.as_object_mut() {
content_obj.insert("_version".to_string(), version.clone());
}
}
ScimToolResult {
success: true,
content,
metadata: Some(metadata),
}
} else {
let error_msg = response
.error
.unwrap_or_else(|| "User not found".to_string());
ScimToolResult {
success: false,
content: json!({
"error": error_msg,
"error_code": if error_msg.contains("not found") { "USER_NOT_FOUND" } else { "GET_USER_FAILED" },
"user_id": user_id
}),
metadata: Some(json!({
"operation": "get_user",
"resource_id": user_id
})),
}
}
}
pub async fn handle_update_user<P: ResourceProvider + Send + Sync + 'static>(
server: &ScimMcpServer<P>,
arguments: Value,
) -> ScimToolResult {
let user_id = match arguments.get("user_id").and_then(|id| id.as_str()) {
Some(id) => id,
None => {
return ScimToolResult {
success: false,
content: json!({"error": "Missing user_id parameter"}),
metadata: None,
};
}
};
let user_data = match arguments.get("user_data") {
Some(data) => data.clone(),
None => {
return ScimToolResult {
success: false,
content: json!({"error": "Missing user_data parameter"}),
metadata: None,
};
}
};
let tenant_context = arguments
.get("tenant_id")
.and_then(|t| t.as_str())
.map(|id| TenantContext::new(id.to_string(), "mcp-client".to_string()));
let mut request =
ScimOperationRequest::update("User".to_string(), user_id.to_string(), user_data);
if let Some(tenant) = tenant_context {
request = request.with_tenant(tenant);
}
if let Some(expected_version_str) = arguments.get("expected_version").and_then(|v| v.as_str()) {
match ScimVersion::parse_raw(expected_version_str) {
Ok(version) => {
request = request.with_expected_version(version);
}
Err(_) => {
return ScimToolResult {
success: false,
content: json!({
"error": format!("Invalid expected_version format: '{}'. Use raw version (e.g., 'abc123def')", expected_version_str),
"error_code": "INVALID_VERSION_FORMAT"
}),
metadata: None,
};
}
}
}
let response = server.operation_handler.handle_operation(request).await;
if response.success {
let mut content = response
.data
.unwrap_or_else(|| json!({"status": "updated"}));
let mut metadata = json!({
"operation": "update_user",
"resource_type": "User",
"resource_id": user_id
});
if let Some(version) = response.metadata.additional.get("version") {
metadata["version"] = version.clone();
if let Some(content_obj) = content.as_object_mut() {
content_obj.insert("_version".to_string(), version.clone());
}
}
ScimToolResult {
success: true,
content,
metadata: Some(metadata),
}
} else {
let error_msg = response
.error
.unwrap_or_else(|| "Update failed".to_string());
let error_code = if error_msg.contains("version mismatch") || error_msg.contains("modified by another client") {
"VERSION_MISMATCH"
} else if error_msg.contains("not found") {
"USER_NOT_FOUND"
} else {
"UPDATE_USER_FAILED"
};
ScimToolResult {
success: false,
content: json!({
"error": error_msg,
"error_code": error_code,
"user_id": user_id
}),
metadata: Some(json!({
"operation": "update_user",
"resource_id": user_id,
"conditional_update": arguments.get("expected_version").is_some()
})),
}
}
}
pub async fn handle_delete_user<P: ResourceProvider + Send + Sync + 'static>(
server: &ScimMcpServer<P>,
arguments: Value,
) -> ScimToolResult {
let user_id = match arguments.get("user_id").and_then(|id| id.as_str()) {
Some(id) => id,
None => {
return ScimToolResult {
success: false,
content: json!({"error": "Missing user_id parameter"}),
metadata: None,
};
}
};
let tenant_context = arguments
.get("tenant_id")
.and_then(|t| t.as_str())
.map(|id| TenantContext::new(id.to_string(), "mcp-client".to_string()));
let mut request = ScimOperationRequest::delete("User".to_string(), user_id.to_string());
if let Some(tenant) = tenant_context {
request = request.with_tenant(tenant);
}
if let Some(expected_version_str) = arguments.get("expected_version").and_then(|v| v.as_str()) {
match ScimVersion::parse_raw(expected_version_str) {
Ok(version) => {
request = request.with_expected_version(version);
}
Err(_) => {
return ScimToolResult {
success: false,
content: json!({
"error": format!("Invalid expected_version format: '{}'. Use raw version (e.g., 'abc123def')", expected_version_str),
"error_code": "INVALID_VERSION_FORMAT"
}),
metadata: None,
};
}
}
}
let response = server.operation_handler.handle_operation(request).await;
if response.success {
ScimToolResult {
success: true,
content: json!({"status": "deleted", "user_id": user_id}),
metadata: Some(json!({
"operation": "delete_user",
"resource_type": "User",
"resource_id": user_id,
"conditional_delete": arguments.get("expected_version").is_some()
})),
}
} else {
let error_msg = response
.error
.unwrap_or_else(|| "Delete failed".to_string());
let error_code = if error_msg.contains("version mismatch") || error_msg.contains("modified by another client") {
"VERSION_MISMATCH"
} else if error_msg.contains("not found") {
"USER_NOT_FOUND"
} else {
"DELETE_USER_FAILED"
};
ScimToolResult {
success: false,
content: json!({
"error": error_msg,
"error_code": error_code,
"user_id": user_id
}),
metadata: Some(json!({
"operation": "delete_user",
"resource_id": user_id,
"conditional_delete": arguments.get("expected_version").is_some()
})),
}
}
}