Files
exchange-mcp/tools/auth.ts
T
2026-07-10 20:17:43 +03:00

206 lines
5.8 KiB
TypeScript

import { type McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod/v4";
import {
clearConfig,
EwsClient,
hasPassword,
loadConfig,
saveConfig,
setPassword,
} from "../client/ews_client.ts";
import { type LoginConfig } from "../utils/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<LoginConfig> = {};
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.",
},
};
},
);
}