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 authentication. Business rules live in `AuthService`.

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::auth::dto::auth::{
    LoginRequest, LogoutResponse, MeResponse, RegisterRequest, TokenResponse,
};
use crate::modules::auth::services::auth_service::AuthService;

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

#[tool_router(router = auth_tools, vis = "pub(crate)")]
impl McpServer {
    /// Create an account and get a bearer token. The first account becomes admin.
    #[tool(annotations(open_world_hint = false))]
    async fn auth_register(
        &self,
        Parameters(input): Parameters<RegisterRequest>,
    ) -> AppResult<Json<TokenResponse>> {
        let session = AuthService::from_ref(&self.state).register(input).await?;
        Ok(Json(session.into()))
    }

    /// Exchange an email and password for a new bearer token.
    #[tool(annotations(open_world_hint = false))]
    async fn auth_login(
        &self,
        Parameters(input): Parameters<LoginRequest>,
    ) -> AppResult<Json<TokenResponse>> {
        let session = AuthService::from_ref(&self.state).login(input).await?;
        Ok(Json(session.into()))
    }

    /// Revoke the bearer token this request was made with.
    #[tool(annotations(idempotent_hint = true, open_world_hint = false))]
    async fn auth_logout(
        &self,
        Extension(parts): Extension<Parts>,
    ) -> AppResult<Json<LogoutResponse>> {
        let user = self.authenticate(&parts).await?;
        AuthService::from_ref(&self.state)
            .logout(user.token_hash())
            .await?;
        Ok(Json(LogoutResponse { revoked: true }))
    }

    /// The signed-in user and their roles.
    #[tool(annotations(read_only_hint = true, open_world_hint = false))]
    async fn auth_me(&self, Extension(parts): Extension<Parts>) -> AppResult<Json<MeResponse>> {
        let user = self.authenticate(&parts).await?;
        Ok(Json(MeResponse {
            id: user.id,
            name: user.name,
            email: user.email,
            roles: user.roles,
        }))
    }
}