import { type McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod/v4"; import { clearConfig, EwsClient, hasPassword, loadConfig, saveConfig, setPassword, } from "../ews_client.ts"; import type { LoginConfig } from "../types/login_config.ts"; export function registerAuthTools(server: McpServer): void { server.registerTool( "login", { description: "Authenticate to Exchange EWS using NTLM credentials." + " On first use all fields except domain are required." + " On subsequent logins only password is needed — previously saved" + " serverUrl, email, username, and domain are reused automatically from config.", inputSchema: z.object({ serverUrl: z.string().optional().describe("EWS server URL"), email: z.string().optional().describe("Email address"), username: z.string().optional().describe("NTLM username"), password: z.string().describe("NTLM password"), domain: z.string().optional().describe("NTLM domain"), }), outputSchema: z.object({ success: z.boolean(), message: z.string().optional(), error: z.string().optional(), }), }, async ({ serverUrl, email, username, password, domain }) => { try { let savedConfig: Partial = {}; try { savedConfig = loadConfig(); } catch { // no saved config — all fields must be provided } const config: LoginConfig = { serverUrl: (serverUrl ?? savedConfig.serverUrl)!, email: (email ?? savedConfig.email)!, username: (username ?? savedConfig.username)!, domain: domain ?? savedConfig.domain ?? "corp", }; if (!config.serverUrl || !config.email || !config.username) { return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: "Missing required fields." + " Provide serverUrl, email, and username, or" + " login once with all fields first.", }), }], }; } config.serverUrl = config.serverUrl.replace(/\/+$/, ""); const client = new EwsClient(config, password); const result = await client.verifyConnection(); if (!result.ok) { return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: result.error ?? "Connection verification failed", }), }], }; } saveConfig(config); return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, message: `Logged in as ${email} to ${serverUrl}`, }), }], }; } catch (error: any) { return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: error.message ?? String(error), }), }], }; } }, ); server.registerTool( "check_session", { description: "Check whether the current EWS session is authenticated. No parameters.", inputSchema: z.object({}), outputSchema: z.object({ authenticated: z.boolean(), email: z.string().optional(), serverUrl: z.string().optional(), error: z.string().optional(), }), }, async () => { try { if (!hasPassword()) { return { content: [{ type: "text" as const, text: JSON.stringify({ authenticated: false, error: "Not logged in. Password not found in memory.", }), }], structuredContent: { authenticated: false, error: "Not logged in. Password not found in memory.", }, }; } const config = loadConfig(); const client = new EwsClient(config); const result = await client.verifyConnection(); return { content: [{ type: "text" as const, text: JSON.stringify({ authenticated: result.ok, email: config.email, serverUrl: config.serverUrl, error: result.error, }), }], structuredContent: { authenticated: result.ok, email: config.email, serverUrl: config.serverUrl, error: result.error, }, }; } catch (error: any) { return { content: [{ type: "text" as const, text: JSON.stringify({ authenticated: false, error: error.message ?? String(error), }), }], structuredContent: { authenticated: false, error: error.message ?? String(error), }, }; } }, ); server.registerTool( "logout", { description: "Clear stored credentials (serverUrl, email, username, domain, password). No parameters.", inputSchema: z.object({}), outputSchema: z.object({ success: z.boolean(), message: z.string().optional(), }), }, async () => { clearConfig(); return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, message: "Logged out. Credentials cleared.", }), }], structuredContent: { success: true, message: "Logged out. Credentials cleared.", }, }; }, ); }