//! 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,
}))
}
}