123 lines
4.0 KiB
TypeScript
123 lines
4.0 KiB
TypeScript
import { type McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
import { z } from "zod/v4";
|
|
import { EwsClient } from "../client/ews_client.ts";
|
|
import { loadConfig } from "../utils/login.ts";
|
|
|
|
export function registerPeopleTools(server: McpServer): void {
|
|
server.registerTool(
|
|
"find_person",
|
|
{
|
|
description:
|
|
"Search for people in the corporate directory (Active Directory)"
|
|
+ " by name, email, or keyword.",
|
|
inputSchema: z.object({
|
|
query: z.string().describe(
|
|
"Name, email address, or keyword to search for",
|
|
),
|
|
}),
|
|
outputSchema: z.object({
|
|
name: z.string(),
|
|
email: z.string(),
|
|
mailboxType: z.string(),
|
|
firstName: z.string(),
|
|
lastName: z.string(),
|
|
jobTitle: z.string(),
|
|
department: z.string(),
|
|
company: z.string(),
|
|
office: z.string(),
|
|
alias: z.string(),
|
|
manager: z.string(),
|
|
managerEmail: z.string(),
|
|
phones: z.record(z.string(), z.string()),
|
|
address: z.string(),
|
|
directReports: z.array(z.object({
|
|
name: z.string(),
|
|
email: z.string(),
|
|
})),
|
|
}),
|
|
},
|
|
async ({ query }) => {
|
|
try {
|
|
const client = new EwsClient(loadConfig());
|
|
const resolutions = await client.resolveNames(query);
|
|
|
|
const people = resolutions.map((r: any) => {
|
|
const mailbox = r.Mailbox ?? {};
|
|
const contact = r.Contact ?? {};
|
|
|
|
const person: any = {
|
|
name: mailbox.Name ?? contact.DisplayName ?? "",
|
|
email: mailbox.EmailAddress ?? "",
|
|
mailboxType: mailbox.MailboxType ?? "",
|
|
firstName: contact.GivenName ?? "",
|
|
lastName: contact.Surname ?? "",
|
|
jobTitle: contact.JobTitle ?? "",
|
|
department: contact.Department ?? "",
|
|
company: contact.CompanyName ?? "",
|
|
office: contact.OfficeLocation ?? "",
|
|
alias: contact.Alias ?? "",
|
|
manager: "",
|
|
managerEmail: "",
|
|
phones: {},
|
|
address: "",
|
|
directReports: [],
|
|
};
|
|
|
|
const phones = contact.PhoneNumbers?.PhoneNumber ?? [];
|
|
const phoneList = Array.isArray(phones) ? phones : [phones];
|
|
for (const p of phoneList) {
|
|
if (p?.Key && p?.PhoneNumber) {
|
|
person.phones[p.Key] = p.PhoneNumber;
|
|
}
|
|
}
|
|
|
|
const addrs = contact.PhysicalAddresses?.PhysicalAddress ?? [];
|
|
const addrList = Array.isArray(addrs) ? addrs : [addrs];
|
|
for (const a of addrList) {
|
|
if (a?.Key === "Business") {
|
|
const parts = [a.Street, a.City, a.PostalCode, a.CountryOrRegion]
|
|
.filter(Boolean);
|
|
if (parts.length) {
|
|
person.address = parts.join(", ");
|
|
}
|
|
}
|
|
}
|
|
|
|
const managerData = contact.ManagerMailbox?.Mailbox ?? {};
|
|
if (managerData.Name || managerData.EmailAddress) {
|
|
person.manager = managerData.Name ?? "";
|
|
person.managerEmail = managerData.EmailAddress ?? "";
|
|
} else if (contact.Manager) {
|
|
person.manager = contact.Manager;
|
|
}
|
|
|
|
const reports = contact.DirectReports?.DirectReport ?? [];
|
|
const reportList = Array.isArray(reports) ? reports : [reports];
|
|
for (const rp of reportList) {
|
|
if (rp?.Name || rp?.EmailAddress) {
|
|
person.directReports.push({
|
|
name: rp.Name ?? "",
|
|
email: rp.EmailAddress ?? "",
|
|
});
|
|
}
|
|
}
|
|
|
|
return person;
|
|
});
|
|
|
|
return {
|
|
content: [{ type: "text" as const, text: JSON.stringify(people) }],
|
|
structuredContent: { people },
|
|
};
|
|
} catch (error: any) {
|
|
return {
|
|
content: [{
|
|
type: "text" as const,
|
|
text: JSON.stringify({ error: error.message ?? String(error) }),
|
|
}],
|
|
};
|
|
}
|
|
},
|
|
);
|
|
}
|