Compare commits
1 Commits
able-swan
...
b1720b8a21
| Author | SHA1 | Date | |
|---|---|---|---|
| b1720b8a21 |
@@ -0,0 +1,8 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
@@ -0,0 +1 @@
|
||||
/.pnp.* binary linguist-generated
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
.cache
|
||||
.data
|
||||
.DS_Store
|
||||
.env
|
||||
.git
|
||||
.idea
|
||||
.pnp.*
|
||||
.target
|
||||
.tmp
|
||||
.vscode
|
||||
.yarn
|
||||
node_modules
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"lineWidth": 80,
|
||||
"indentWidth": 2,
|
||||
"typescript": {
|
||||
"module.sortImportDeclarations": "caseInsensitive",
|
||||
"module.sortExportDeclarations": "caseInsensitive"
|
||||
},
|
||||
"excludes": [
|
||||
"**/.git",
|
||||
"**/.target"
|
||||
],
|
||||
"plugins": [
|
||||
"https://plugins.dprint.dev/typescript-0.91.1.wasm",
|
||||
"https://plugins.dprint.dev/json-0.17.4.wasm",
|
||||
"https://plugins.dprint.dev/markdown-0.15.3.wasm",
|
||||
"https://plugins.dprint.dev/dockerfile-0.3.0.wasm"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import { XMLParser } from "fast-xml-parser";
|
||||
import { promisify } from "node:util";
|
||||
import { env } from "node:process";
|
||||
import { createRequire } from "node:module";
|
||||
import https from "node:https";
|
||||
|
||||
const ntlm: any = createRequire(import.meta.url)("httpntlm");
|
||||
const postAsync = promisify(ntlm.post.bind(ntlm));
|
||||
|
||||
const SSL_OP_LEGACY_SERVER_CONNECT = 0x00000004;
|
||||
|
||||
const AGENT = new https.Agent({
|
||||
keepAlive: true,
|
||||
rejectUnauthorized: false,
|
||||
secureOptions: SSL_OP_LEGACY_SERVER_CONNECT,
|
||||
});
|
||||
|
||||
const EWS_URL = "https://mail.b1.ru/EWS/Exchange.asmx";
|
||||
|
||||
const PARSER = new XMLParser({
|
||||
ignoreAttributes: false,
|
||||
attributeNamePrefix: "@_",
|
||||
removeNSPrefix: true,
|
||||
textNodeName: "#text",
|
||||
});
|
||||
|
||||
function buildSoapEnvelope(body: string): string {
|
||||
return `<?xml version="1.0" encoding="utf-8"?>
|
||||
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
|
||||
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
|
||||
<s:Body>
|
||||
${body}
|
||||
</s:Body>
|
||||
</s:Envelope>`;
|
||||
}
|
||||
|
||||
async function ewsSoap(options: { body: string; soapAction: string }): Promise<any> {
|
||||
const res = await postAsync({
|
||||
url: EWS_URL,
|
||||
username: env.EWS_USERNAME ?? "polina.litvinova",
|
||||
domain: "corp",
|
||||
password: env.EWS_PASSWORD,
|
||||
agent: AGENT,
|
||||
headers: {
|
||||
"Content-Type": "text/xml; charset=utf-8",
|
||||
SOAPAction: options.soapAction,
|
||||
},
|
||||
body: options.body,
|
||||
});
|
||||
|
||||
if (typeof res.body !== "string") {
|
||||
throw new Error(`NTLM request failed, status=${res.statusCode}`);
|
||||
}
|
||||
return PARSER.parse(res.body);
|
||||
}
|
||||
|
||||
async function getFolder() {
|
||||
const soap = buildSoapEnvelope(`\
|
||||
<m:GetFolder>
|
||||
<m:FolderShape>
|
||||
<t:BaseShape>IdOnly</t:BaseShape>
|
||||
<t:AdditionalProperties>
|
||||
<t:FieldURI FieldURI="folder:DisplayName"/>
|
||||
<t:FieldURI FieldURI="folder:TotalCount"/>
|
||||
<t:FieldURI FieldURI="folder:UnreadCount"/>
|
||||
</t:AdditionalProperties>
|
||||
</m:FolderShape>
|
||||
<m:FolderIds>
|
||||
<t:DistinguishedFolderId Id="inbox"/>
|
||||
</m:FolderIds>
|
||||
</m:GetFolder>`);
|
||||
|
||||
const data = await ewsSoap({
|
||||
body: soap,
|
||||
soapAction: "http://schemas.microsoft.com/exchange/services/2006/messages/GetFolder",
|
||||
});
|
||||
|
||||
const rm = data.Envelope?.Body?.GetFolderResponse?.ResponseMessages;
|
||||
const msg = rm?.GetFolderResponseMessage;
|
||||
const folder = msg?.Folders?.Folder;
|
||||
|
||||
console.log(`DisplayName: ${folder?.DisplayName}`);
|
||||
console.log(`FolderId: ${folder?.FolderId?.["@_Id"]}`);
|
||||
console.log(`Total items: ${folder?.TotalCount}`);
|
||||
console.log(`Unread: ${folder?.UnreadCount}`);
|
||||
}
|
||||
|
||||
async function getLastMessages() {
|
||||
const soap = buildSoapEnvelope(`\
|
||||
<m:FindItem Traversal="Shallow">
|
||||
<m:ItemShape>
|
||||
<t:BaseShape>AllProperties</t:BaseShape>
|
||||
</m:ItemShape>
|
||||
<m:IndexedPageItemView MaxEntriesReturned="3" Offset="0" BasePoint="Beginning"/>
|
||||
<m:ParentFolderIds>
|
||||
<t:DistinguishedFolderId Id="inbox"/>
|
||||
</m:ParentFolderIds>
|
||||
<m:SortOrder>
|
||||
<t:FieldOrder Order="Descending">
|
||||
<t:FieldURI FieldURI="item:DateTimeReceived"/>
|
||||
</t:FieldOrder>
|
||||
</m:SortOrder>
|
||||
</m:FindItem>`);
|
||||
|
||||
const data = await ewsSoap({
|
||||
body: soap,
|
||||
soapAction: "http://schemas.microsoft.com/exchange/services/2006/messages/FindItem",
|
||||
});
|
||||
|
||||
const rm = data.Envelope?.Body?.FindItemResponse?.ResponseMessages;
|
||||
const msg = rm?.FindItemResponseMessage;
|
||||
const rootFolder = msg?.RootFolder;
|
||||
const items = rootFolder?.Items;
|
||||
const messagesList: any[] = items?.Message ? (Array.isArray(items.Message) ? items.Message : [items.Message]) : [];
|
||||
|
||||
if (!messagesList.length) {
|
||||
console.log("\n--- No messages found ---");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`\n--- ${messagesList.length} message(s) ---`);
|
||||
for (const m of messagesList) {
|
||||
const mbox = m.From?.Mailbox;
|
||||
const author = mbox ? `${mbox.Name ?? "(no name)"} <${mbox.EmailAddress ?? "(no email)"}>` : "(unknown)";
|
||||
console.log(`\nSubject: ${m.Subject ?? "(no subject)"}`);
|
||||
console.log(`From: ${author}`);
|
||||
console.log(`Date: ${m.DateTimeReceived ?? "(unknown)"}`);
|
||||
console.log(`Preview: ${(m.Preview ?? "(no preview)").slice(0, 200)}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (!env.EWS_PASSWORD) {
|
||||
console.error("Set EWS_PASSWORD environment variable");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
await getFolder();
|
||||
await getLastMessages();
|
||||
} catch (err) {
|
||||
console.error("Error:", err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Generated
+238
@@ -0,0 +1,238 @@
|
||||
{
|
||||
"name": "exchange-mcp",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "exchange-mcp",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"fast-xml-parser": "^5.2.0",
|
||||
"httpntlm": "^1.8.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodable/entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/nodable"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz",
|
||||
"integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/anynum": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz",
|
||||
"integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/des.js": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
|
||||
"integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-xml-builder": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.1.tgz",
|
||||
"integrity": "sha512-tPb5TTWfgfVx5BNSi2xV0eLr89POeXXn0dXIsCJ9m1narrWxeIyx6je9d7Rce/3NyXLbvuQmLkxq+RuxMWejvw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-expression-matcher": "^1.5.0",
|
||||
"xml-naming": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.9.3.tgz",
|
||||
"integrity": "sha512-brCNCeScma/kqa54J4PIDriSSSLssRkuYaUCpvHJulGc3HGI/xxKUCTDcYkAdqJsyb//ydpbxecjC3hB9+tb/g==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodable/entities": "^2.2.0",
|
||||
"fast-xml-builder": "^1.2.0",
|
||||
"is-unsafe": "^1.0.1",
|
||||
"path-expression-matcher": "^1.5.0",
|
||||
"strnum": "^2.4.1",
|
||||
"xml-naming": "^0.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"fxparser": "src/cli/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/httpntlm": {
|
||||
"version": "1.8.13",
|
||||
"resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.8.13.tgz",
|
||||
"integrity": "sha512-2F2FDPiWT4rewPzNMg3uPhNkP3NExENlUGADRUDPQvuftuUTGW98nLZtGemCIW3G40VhWZYgkIDcQFAwZ3mf2Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://www.paypal.com/donate/?hosted_button_id=2CKNJLZJBW8ZC"
|
||||
},
|
||||
{
|
||||
"type": "buymeacoffee",
|
||||
"url": "https://www.buymeacoffee.com/samdecrock"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"des.js": "^1.0.1",
|
||||
"httpreq": ">=0.4.22",
|
||||
"js-md4": "^0.3.2",
|
||||
"underscore": "~1.12.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/httpreq": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/httpreq/-/httpreq-1.1.1.tgz",
|
||||
"integrity": "sha512-uhSZLPPD2VXXOSN8Cni3kIsoFHaU2pT/nySEU/fHr/ePbqHYr0jeiQRmUKLEirC09SFPsdMoA7LU7UXMd/w0Kw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6.15.1"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/is-unsafe": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-1.0.1.tgz",
|
||||
"integrity": "sha512-CLK2+VdgERgD96EYm5lUQssZYlRg2tkZnbsxZoacmSiRxiFJ4Nk4SzjCl+Ur+v3kXIY9dTIdb3IH22y1mZ56LA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-md4": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz",
|
||||
"integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/path-expression-matcher": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz",
|
||||
"integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strnum": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz",
|
||||
"integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anynum": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/underscore": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz",
|
||||
"integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/xml-naming": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz",
|
||||
"integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "exchange-mcp",
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"fast-xml-parser": "^5.2.0",
|
||||
"httpntlm": "^1.8.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowImportingTsExtensions": true,
|
||||
"allowUnreachableCode": false,
|
||||
"allowUnusedLabels": false,
|
||||
"checkJs": false,
|
||||
"erasableSyntaxOnly": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"keyofStringsOnly": false,
|
||||
"lib": [
|
||||
"esnext"
|
||||
],
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"noEmit": true,
|
||||
"noErrorTruncation": false,
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": false,
|
||||
"noImplicitThis": true,
|
||||
"noStrictGenericChecks": false,
|
||||
"noUncheckedIndexedAccess": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"strictBindCallApply": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictNullChecks": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"suppressExcessPropertyErrors": false,
|
||||
"suppressImplicitAnyIndexErrors": false,
|
||||
"target": "esnext",
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"useUnknownInCatchVariables": true,
|
||||
"verbatimModuleSyntax": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user