slave 0.4.0

Laravel-inspired CLI for Rust MCP servers: scaffold apps whose business operations are MCP tools over Streamable HTTP, with built-in auth, users, roles and Turso migrations
//! MCP tools for users. Business rules live in `UserService`.

use axum::extract::FromRef;
use axum::http::request::Parts;
use rmcp::handler::server::router::tool::ToolRouter;
use rmcp::handler::server::tool::Extension;
use rmcp::handler::server::wrapper::{Json, Parameters};
use rmcp::{tool, tool_router};

use crate::base::error::AppResult;
use crate::base::mcp::McpServer;
use crate::modules::user::dto::user::{
    DeletedUserResponse, UserIdRequest, UserListResponse, UserResponse,
};
use crate::modules::user::services::user_service::UserService;

pub fn tools() -> ToolRouter<McpServer> {
    McpServer::user_tools()
}

#[tool_router(router = user_tools, vis = "pub(crate)")]
impl McpServer {
    /// List all users (admin only).
    #[tool(annotations(read_only_hint = true, open_world_hint = false))]
    async fn user_list(
        &self,
        Extension(parts): Extension<Parts>,
    ) -> AppResult<Json<UserListResponse>> {
        self.authenticate_admin(&parts).await?;
        let users = UserService::from_ref(&self.state).list().await?;
        Ok(Json(UserListResponse {
            users: users.into_iter().map(UserResponse::from).collect(),
        }))
    }

    /// Show a user. Admins can view anyone, other users only themselves.
    #[tool(annotations(read_only_hint = true, open_world_hint = false))]
    async fn user_get(
        &self,
        Extension(parts): Extension<Parts>,
        Parameters(input): Parameters<UserIdRequest>,
    ) -> AppResult<Json<UserResponse>> {
        let user = self.authenticate(&parts).await?;
        user.require_self_or_admin(input.user_id)?;
        let found = UserService::from_ref(&self.state)
            .find(input.user_id)
            .await?;
        Ok(Json(found.into()))
    }

    /// Delete a user and revoke their tokens (admin only; never yourself).
    #[tool(annotations(destructive_hint = true, open_world_hint = false))]
    async fn user_delete(
        &self,
        Extension(parts): Extension<Parts>,
        Parameters(input): Parameters<UserIdRequest>,
    ) -> AppResult<Json<DeletedUserResponse>> {
        let admin = self.authenticate_admin(&parts).await?;
        UserService::from_ref(&self.state)
            .delete(input.user_id, admin.id)
            .await?;
        Ok(Json(DeletedUserResponse {
            deleted: true,
            id: input.user_id,
        }))
    }
}