@chrischall/office-outlook-mcp 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/bundle.js +265 -24
- package/dist/tools/writes.js +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/server.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "MCP server for Outlook / Microsoft 365 — mail, calendar, contacts and tasks via natural language",
|
|
10
|
-
"version": "0.7.
|
|
10
|
+
"version": "0.7.1"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"displayName": "Outlook (Microsoft 365)",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"description": "MCP server for Outlook / Microsoft 365 — triage unread mail, reply, answer meeting invites and schedule meetings, plus folders, calendar, contacts and tasks, with confirmation before anything is sent",
|
|
18
|
-
"version": "0.7.
|
|
18
|
+
"version": "0.7.1",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Hall"
|
|
21
21
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "office-outlook-mcp",
|
|
3
3
|
"displayName": "Outlook (Microsoft 365)",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.1",
|
|
5
5
|
"description": "Outlook / Microsoft 365 for Claude — triage unread mail, reply, answer meeting invites and schedule meetings, plus folders, calendar, contacts and tasks, with confirmation before anything is sent, using your signed-in browser session",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Chris Hall",
|
package/dist/bundle.js
CHANGED
|
@@ -35575,7 +35575,8 @@ var init_errors3 = __esm({
|
|
|
35575
35575
|
HEADER_SECRET_RE = new RegExp(`(\\b(?:x[-_]${HEADER_NAME_RUN}?(?:api[-_]?key|token|secret|auth)${HEADER_NAME_RUN}|api[-_]?key)\\s*:\\s*)[^\\s,;"'<>\`]+`, "gi");
|
|
35576
35576
|
AWS_SIGV4_RE = /([?&]X-Amz-(?:Signature|Security-Token|Credential)=)[^&#\s"'<>`]+/gi;
|
|
35577
35577
|
JSON_SECRET_KEYS = [
|
|
35578
|
-
"(?:access|refresh|id|auth|session|bearer|csrf|xsrf)[_-]?token",
|
|
35578
|
+
"(?:access|refresh|id|auth|session|bearer|csrf|xsrf|api)[_-]?token",
|
|
35579
|
+
// api: fleet-audit#1444 (Pipedrive/Todoist-style, as in QUERY_SECRET_RE)
|
|
35579
35580
|
"client[_-]?secret",
|
|
35580
35581
|
"api[_-]?secret",
|
|
35581
35582
|
"(?:x[_-])?api[_-]?key",
|
|
@@ -37347,6 +37348,154 @@ var init_transport_failure = __esm({
|
|
|
37347
37348
|
}
|
|
37348
37349
|
});
|
|
37349
37350
|
|
|
37351
|
+
// node_modules/@chrischall/mcp-utils/dist/netguard/address.js
|
|
37352
|
+
function isPublicAddress(ip) {
|
|
37353
|
+
const v4 = parseIPv4(ip);
|
|
37354
|
+
if (v4)
|
|
37355
|
+
return isPublicIPv4(v4);
|
|
37356
|
+
const v6 = parseIPv6(ip);
|
|
37357
|
+
if (v6)
|
|
37358
|
+
return isPublicIPv6(v6);
|
|
37359
|
+
return false;
|
|
37360
|
+
}
|
|
37361
|
+
function parseIPv4(text) {
|
|
37362
|
+
if (!/^(?:0|[1-9]\d{0,2})(?:\.(?:0|[1-9]\d{0,2})){3}$/.test(text))
|
|
37363
|
+
return void 0;
|
|
37364
|
+
const octets = text.split(".").map(Number);
|
|
37365
|
+
return octets.every((o) => o <= 255) ? octets : void 0;
|
|
37366
|
+
}
|
|
37367
|
+
function parseIPv6(text) {
|
|
37368
|
+
if (!/^[0-9a-fA-F:.]+$/.test(text) || !text.includes(":"))
|
|
37369
|
+
return void 0;
|
|
37370
|
+
const halves = text.split("::");
|
|
37371
|
+
if (halves.length > 2)
|
|
37372
|
+
return void 0;
|
|
37373
|
+
const groups = (part) => {
|
|
37374
|
+
if (part === "")
|
|
37375
|
+
return [];
|
|
37376
|
+
const out = [];
|
|
37377
|
+
const pieces = part.split(":");
|
|
37378
|
+
for (const [i, piece] of pieces.entries()) {
|
|
37379
|
+
if (i === pieces.length - 1 && piece.includes(".")) {
|
|
37380
|
+
const v4 = parseIPv4(piece);
|
|
37381
|
+
if (!v4)
|
|
37382
|
+
return void 0;
|
|
37383
|
+
const [a = 0, b = 0, c = 0, d = 0] = v4;
|
|
37384
|
+
out.push(a << 8 | b, c << 8 | d);
|
|
37385
|
+
continue;
|
|
37386
|
+
}
|
|
37387
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(piece))
|
|
37388
|
+
return void 0;
|
|
37389
|
+
out.push(parseInt(piece, 16));
|
|
37390
|
+
}
|
|
37391
|
+
return out;
|
|
37392
|
+
};
|
|
37393
|
+
const head = groups(halves[0] ?? "");
|
|
37394
|
+
const tail = halves.length === 2 ? groups(halves[1] ?? "") : [];
|
|
37395
|
+
if (!head || !tail)
|
|
37396
|
+
return void 0;
|
|
37397
|
+
const fill = 8 - head.length - tail.length;
|
|
37398
|
+
if (halves.length === 2 ? fill < 1 : fill !== 0)
|
|
37399
|
+
return void 0;
|
|
37400
|
+
const words = [...head, ...new Array(fill).fill(0), ...tail];
|
|
37401
|
+
const bytes = [];
|
|
37402
|
+
for (const w of words)
|
|
37403
|
+
bytes.push(w >> 8, w & 255);
|
|
37404
|
+
return bytes;
|
|
37405
|
+
}
|
|
37406
|
+
function inRange(bytes, prefix, bits) {
|
|
37407
|
+
for (let i = 0; i < bits; i += 1) {
|
|
37408
|
+
const byte = i >> 3;
|
|
37409
|
+
const mask = 128 >> (i & 7);
|
|
37410
|
+
if (((bytes[byte] ?? 0) & mask) !== ((prefix[byte] ?? 0) & mask))
|
|
37411
|
+
return false;
|
|
37412
|
+
}
|
|
37413
|
+
return true;
|
|
37414
|
+
}
|
|
37415
|
+
function isPublicIPv4(octets) {
|
|
37416
|
+
return !BLOCKED_V4.some(([prefix, bits]) => inRange(octets, prefix, bits));
|
|
37417
|
+
}
|
|
37418
|
+
function isPublicIPv6(bytes) {
|
|
37419
|
+
if (inRange(bytes, MAPPED_V4, 96) || inRange(bytes, SIIT_V4, 96) || inRange(bytes, NAT64, 96)) {
|
|
37420
|
+
return isPublicIPv4(bytes.slice(12, 16));
|
|
37421
|
+
}
|
|
37422
|
+
if (inRange(bytes, SIX_TO_FOUR, 16))
|
|
37423
|
+
return isPublicIPv4(bytes.slice(2, 6));
|
|
37424
|
+
return !BLOCKED_V6.some(([prefix, bits]) => inRange(bytes, prefix, bits));
|
|
37425
|
+
}
|
|
37426
|
+
var BLOCKED_V4, V6, BLOCKED_V6, MAPPED_V4, SIIT_V4, NAT64, SIX_TO_FOUR;
|
|
37427
|
+
var init_address = __esm({
|
|
37428
|
+
"node_modules/@chrischall/mcp-utils/dist/netguard/address.js"() {
|
|
37429
|
+
BLOCKED_V4 = [
|
|
37430
|
+
[[0, 0, 0, 0], 8],
|
|
37431
|
+
// this network
|
|
37432
|
+
[[10, 0, 0, 0], 8],
|
|
37433
|
+
// RFC 1918
|
|
37434
|
+
[[100, 64, 0, 0], 10],
|
|
37435
|
+
// CGNAT
|
|
37436
|
+
[[127, 0, 0, 0], 8],
|
|
37437
|
+
// loopback
|
|
37438
|
+
[[169, 254, 0, 0], 16],
|
|
37439
|
+
// link-local, incl. cloud metadata
|
|
37440
|
+
[[172, 16, 0, 0], 12],
|
|
37441
|
+
// RFC 1918
|
|
37442
|
+
[[192, 0, 0, 0], 24],
|
|
37443
|
+
// IETF protocol assignments
|
|
37444
|
+
[[192, 0, 2, 0], 24],
|
|
37445
|
+
// TEST-NET-1
|
|
37446
|
+
[[192, 88, 99, 0], 24],
|
|
37447
|
+
// 6to4 relay anycast (deprecated)
|
|
37448
|
+
[[192, 168, 0, 0], 16],
|
|
37449
|
+
// RFC 1918
|
|
37450
|
+
[[198, 18, 0, 0], 15],
|
|
37451
|
+
// benchmarking
|
|
37452
|
+
[[198, 51, 100, 0], 24],
|
|
37453
|
+
// TEST-NET-2
|
|
37454
|
+
[[203, 0, 113, 0], 24],
|
|
37455
|
+
// TEST-NET-3
|
|
37456
|
+
[[224, 0, 0, 0], 4],
|
|
37457
|
+
// multicast
|
|
37458
|
+
[[240, 0, 0, 0], 4]
|
|
37459
|
+
// reserved + broadcast
|
|
37460
|
+
];
|
|
37461
|
+
V6 = (hex3) => parseIPv6(hex3);
|
|
37462
|
+
BLOCKED_V6 = [
|
|
37463
|
+
[V6("::"), 96],
|
|
37464
|
+
// ::, ::1 and the deprecated IPv4-compatible form, refused whole
|
|
37465
|
+
[V6("64:ff9b:1::"), 48],
|
|
37466
|
+
// local-use NAT64 (RFC 8215)
|
|
37467
|
+
[V6("100::"), 64],
|
|
37468
|
+
// discard-only
|
|
37469
|
+
[V6("2001::"), 32],
|
|
37470
|
+
// Teredo
|
|
37471
|
+
[V6("2001:2::"), 48],
|
|
37472
|
+
// benchmarking
|
|
37473
|
+
[V6("2001:10::"), 28],
|
|
37474
|
+
// ORCHID (deprecated)
|
|
37475
|
+
[V6("2001:20::"), 28],
|
|
37476
|
+
// ORCHIDv2
|
|
37477
|
+
[V6("2001:db8::"), 32],
|
|
37478
|
+
// documentation
|
|
37479
|
+
[V6("3fff::"), 20],
|
|
37480
|
+
// documentation (RFC 9637)
|
|
37481
|
+
[V6("5f00::"), 16],
|
|
37482
|
+
// SRv6 SIDs
|
|
37483
|
+
[V6("fc00::"), 7],
|
|
37484
|
+
// unique local
|
|
37485
|
+
[V6("fe80::"), 10],
|
|
37486
|
+
// link-local
|
|
37487
|
+
[V6("fec0::"), 10],
|
|
37488
|
+
// site-local (deprecated)
|
|
37489
|
+
[V6("ff00::"), 8]
|
|
37490
|
+
// multicast
|
|
37491
|
+
];
|
|
37492
|
+
MAPPED_V4 = V6("::ffff:0:0");
|
|
37493
|
+
SIIT_V4 = V6("::ffff:0:0:0");
|
|
37494
|
+
NAT64 = V6("64:ff9b::");
|
|
37495
|
+
SIX_TO_FOUR = V6("2002::");
|
|
37496
|
+
}
|
|
37497
|
+
});
|
|
37498
|
+
|
|
37350
37499
|
// node_modules/@chrischall/mcp-utils/dist/internal/retry-after.js
|
|
37351
37500
|
function retryAfterToMs(header, now = Date.now()) {
|
|
37352
37501
|
if (header == null)
|
|
@@ -37366,6 +37515,44 @@ var init_retry_after = __esm({
|
|
|
37366
37515
|
}
|
|
37367
37516
|
});
|
|
37368
37517
|
|
|
37518
|
+
// node_modules/@chrischall/mcp-utils/dist/internal/sleep.js
|
|
37519
|
+
function abortReason(signal) {
|
|
37520
|
+
return signal.reason ?? new DOMException("This operation was aborted", "AbortError");
|
|
37521
|
+
}
|
|
37522
|
+
function cancellableSleep(ms, sleep3) {
|
|
37523
|
+
const signal = currentCallSignal();
|
|
37524
|
+
if (signal?.aborted)
|
|
37525
|
+
return Promise.reject(abortReason(signal));
|
|
37526
|
+
if (!signal)
|
|
37527
|
+
return sleep3 ? sleep3(ms) : new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
37528
|
+
return new Promise((resolve5, reject) => {
|
|
37529
|
+
let timer;
|
|
37530
|
+
const onAbort = () => {
|
|
37531
|
+
if (timer !== void 0)
|
|
37532
|
+
clearTimeout(timer);
|
|
37533
|
+
reject(abortReason(signal));
|
|
37534
|
+
};
|
|
37535
|
+
const done = () => {
|
|
37536
|
+
signal.removeEventListener("abort", onAbort);
|
|
37537
|
+
resolve5();
|
|
37538
|
+
};
|
|
37539
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
37540
|
+
if (sleep3) {
|
|
37541
|
+
sleep3(ms).then(done, (err) => {
|
|
37542
|
+
signal.removeEventListener("abort", onAbort);
|
|
37543
|
+
reject(err);
|
|
37544
|
+
});
|
|
37545
|
+
} else {
|
|
37546
|
+
timer = setTimeout(done, ms);
|
|
37547
|
+
}
|
|
37548
|
+
});
|
|
37549
|
+
}
|
|
37550
|
+
var init_sleep = __esm({
|
|
37551
|
+
"node_modules/@chrischall/mcp-utils/dist/internal/sleep.js"() {
|
|
37552
|
+
init_cancel();
|
|
37553
|
+
}
|
|
37554
|
+
});
|
|
37555
|
+
|
|
37369
37556
|
// node_modules/@chrischall/mcp-utils/dist/http/index.js
|
|
37370
37557
|
function withoutCredentials(headers, tokenHeader) {
|
|
37371
37558
|
const drop = new Set(CROSS_ORIGIN_DROPPED_HEADERS);
|
|
@@ -37417,6 +37604,9 @@ async function writeOrUnknown(run, onUnknown) {
|
|
|
37417
37604
|
return { ok: false, result: await onUnknown(err, unknownOutcomeReason(err)) };
|
|
37418
37605
|
}
|
|
37419
37606
|
}
|
|
37607
|
+
function isOutcomeUnknownStatus(status) {
|
|
37608
|
+
return status >= 500 && status <= 599 && status !== 501 && status !== 505;
|
|
37609
|
+
}
|
|
37420
37610
|
function headerOf(headers, name) {
|
|
37421
37611
|
if (headers === void 0)
|
|
37422
37612
|
return void 0;
|
|
@@ -37532,7 +37722,7 @@ function createApiClient(opts) {
|
|
|
37532
37722
|
const retry = opts.retry ?? DEFAULT_RETRY;
|
|
37533
37723
|
const service = opts.serviceName ?? hostOf(opts.baseUrl);
|
|
37534
37724
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
37535
|
-
const sleep3 = opts.sleep
|
|
37725
|
+
const sleep3 = (ms) => cancellableSleep(ms, opts.sleep);
|
|
37536
37726
|
const unauthorized = () => opts.onUnauthorized ? opts.onUnauthorized() : new UnauthorizedError(service);
|
|
37537
37727
|
const retryStatuses = retry.statuses ?? [429];
|
|
37538
37728
|
const timeoutMs = opts.timeout === false ? 0 : opts.timeout ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
@@ -37547,6 +37737,7 @@ function createApiClient(opts) {
|
|
|
37547
37737
|
}
|
|
37548
37738
|
const authHeader = (token) => !token ? {} : opts.tokenHeader ? { [opts.tokenHeader]: token } : { Authorization: `Bearer ${token}` };
|
|
37549
37739
|
const transportFailures = /* @__PURE__ */ new WeakSet();
|
|
37740
|
+
const answered5xx = /* @__PURE__ */ new WeakSet();
|
|
37550
37741
|
const markTransportFailure = (err) => {
|
|
37551
37742
|
if (typeof err === "object" && err !== null && err.name !== "AbortError") {
|
|
37552
37743
|
transportFailures.add(err);
|
|
@@ -37626,7 +37817,7 @@ function createApiClient(opts) {
|
|
|
37626
37817
|
const baseParts = (() => {
|
|
37627
37818
|
try {
|
|
37628
37819
|
const u = new URL(base);
|
|
37629
|
-
return { origin: u.origin, username: u.username, password: u.password };
|
|
37820
|
+
return { origin: u.origin, hostname: u.hostname, username: u.username, password: u.password };
|
|
37630
37821
|
} catch {
|
|
37631
37822
|
return void 0;
|
|
37632
37823
|
}
|
|
@@ -37666,6 +37857,15 @@ function createApiClient(opts) {
|
|
|
37666
37857
|
const next = new URL(href);
|
|
37667
37858
|
return baseOrigin !== void 0 && next.origin === baseOrigin && next.username === baseParts?.username && next.password === baseParts?.password;
|
|
37668
37859
|
}
|
|
37860
|
+
function isNonPublicLiteralHost(hostname3) {
|
|
37861
|
+
const host = hostname3.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
|
|
37862
|
+
if (host === "localhost" || host.endsWith(".localhost"))
|
|
37863
|
+
return true;
|
|
37864
|
+
if (/^[\d.]+$/.test(host) || host.includes(":"))
|
|
37865
|
+
return !isPublicAddress(host);
|
|
37866
|
+
return false;
|
|
37867
|
+
}
|
|
37868
|
+
const baseIsPublic = baseParts !== void 0 && !isNonPublicLiteralHost(baseParts.hostname);
|
|
37669
37869
|
function sameOriginHop(location, from) {
|
|
37670
37870
|
const href = resolveLocation(location, from);
|
|
37671
37871
|
const next = new URL(href);
|
|
@@ -37718,7 +37918,11 @@ function createApiClient(opts) {
|
|
|
37718
37918
|
}
|
|
37719
37919
|
if (stripCrossOrigin) {
|
|
37720
37920
|
hopUrl = resolveLocation(location, hopUrl);
|
|
37721
|
-
|
|
37921
|
+
const offOrigin = !onBaseOrigin(hopUrl);
|
|
37922
|
+
if (offOrigin && baseIsPublic && isNonPublicLiteralHost(new URL(hopUrl).hostname)) {
|
|
37923
|
+
throw new RedirectRefusedError(`Refusing redirect from ${service} to ${new URL(hopUrl).origin}: it is not a public address (loopback, link-local or a private network), so nothing is sent there.`);
|
|
37924
|
+
}
|
|
37925
|
+
if (credentialed && offOrigin)
|
|
37722
37926
|
credentialed = false;
|
|
37723
37927
|
} else {
|
|
37724
37928
|
hopUrl = sameOriginHop(location, hopUrl);
|
|
@@ -37793,19 +37997,22 @@ function createApiClient(opts) {
|
|
|
37793
37997
|
hint: opts.writeOutcomeHint
|
|
37794
37998
|
});
|
|
37795
37999
|
}
|
|
37796
|
-
if (typeof err === "object" && err !== null && transportFailures.has(err)) {
|
|
38000
|
+
if (typeof err === "object" && err !== null && (transportFailures.has(err) || answered5xx.has(err))) {
|
|
37797
38001
|
throw new WriteOutcomeUnknownError(service, method, { cause: err, hint: opts.writeOutcomeHint });
|
|
37798
38002
|
}
|
|
37799
38003
|
throw err;
|
|
37800
38004
|
}
|
|
37801
38005
|
}
|
|
37802
|
-
function withIdempotency(opt) {
|
|
38006
|
+
function withIdempotency(method, opt) {
|
|
37803
38007
|
const name = opts.idempotencyHeader;
|
|
37804
38008
|
if (name === void 0 || name === "")
|
|
37805
38009
|
return opt;
|
|
37806
38010
|
const lower2 = name.toLowerCase();
|
|
37807
38011
|
if (opt.headers && Object.keys(opt.headers).some((k) => k.toLowerCase() === lower2))
|
|
37808
38012
|
return opt;
|
|
38013
|
+
const repeatable = opt.idempotent === true || SAFE_METHODS.has(method.toUpperCase());
|
|
38014
|
+
if (opt.idempotencyKey === void 0 && repeatable)
|
|
38015
|
+
return opt;
|
|
37809
38016
|
const key = opt.idempotencyKey ?? globalThis.crypto.randomUUID();
|
|
37810
38017
|
return { ...opt, headers: { ...opt.headers, [name]: key } };
|
|
37811
38018
|
}
|
|
@@ -37820,18 +38027,21 @@ function createApiClient(opts) {
|
|
|
37820
38027
|
if (decision === "retry" && !retried)
|
|
37821
38028
|
return "retry";
|
|
37822
38029
|
}
|
|
37823
|
-
|
|
38030
|
+
const err = httpError(res, text, method, path, service);
|
|
38031
|
+
if (isOutcomeUnknownStatus(res.status) && !(err instanceof EdgeBlockedError))
|
|
38032
|
+
answered5xx.add(err);
|
|
38033
|
+
return err;
|
|
37824
38034
|
}
|
|
37825
38035
|
const fetchJson = (method, path, opt = {}) => {
|
|
37826
|
-
const o = withIdempotency(opt);
|
|
38036
|
+
const o = withIdempotency(method, opt);
|
|
37827
38037
|
return guardWrite(method, o, (dispatch) => fetchJsonOnce(method, path, o, dispatch));
|
|
37828
38038
|
};
|
|
37829
38039
|
const fetchHtml = (method, path, opt = {}) => {
|
|
37830
|
-
const o = withIdempotency(opt);
|
|
38040
|
+
const o = withIdempotency(method, opt);
|
|
37831
38041
|
return guardWrite(method, o, (dispatch) => fetchHtmlOnce(method, path, o, dispatch));
|
|
37832
38042
|
};
|
|
37833
38043
|
const fetchRaw = (method, path, opt = {}) => {
|
|
37834
|
-
const o = withIdempotency(opt);
|
|
38044
|
+
const o = withIdempotency(method, opt);
|
|
37835
38045
|
return guardWrite(method, o, (dispatch) => fetchRawOnce(method, path, o, dispatch));
|
|
37836
38046
|
};
|
|
37837
38047
|
async function fetchJsonOnce(method, path, opt, dispatch) {
|
|
@@ -37973,7 +38183,7 @@ function decodeJwtExp(token) {
|
|
|
37973
38183
|
}
|
|
37974
38184
|
return exp;
|
|
37975
38185
|
}
|
|
37976
|
-
var DEFAULT_RETRY,
|
|
38186
|
+
var DEFAULT_RETRY, DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_MAX_REDIRECTS, FETCH_MAX_REDIRECTS, CROSS_ORIGIN_DROPPED_HEADERS, REDIRECT_STATUSES, UnauthorizedError, RateLimitedError, RequestTimeoutError, DEFAULT_WRITE_OUTCOME_HINT, WriteOutcomeUnknownError, SAFE_METHODS, ApiError, EdgeBlockedError, EDGE_BLOCK_SCAN_MAX, EDGE_BLOCK_MARKERS;
|
|
37977
38187
|
var init_http = __esm({
|
|
37978
38188
|
"node_modules/@chrischall/mcp-utils/dist/http/index.js"() {
|
|
37979
38189
|
init_headers();
|
|
@@ -37989,9 +38199,10 @@ var init_http = __esm({
|
|
|
37989
38199
|
init_body_limit();
|
|
37990
38200
|
init_net_atoms();
|
|
37991
38201
|
init_url_safety();
|
|
38202
|
+
init_address();
|
|
37992
38203
|
init_retry_after();
|
|
38204
|
+
init_sleep();
|
|
37993
38205
|
DEFAULT_RETRY = { count: 1, delayMs: 2e3 };
|
|
37994
|
-
defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
37995
38206
|
DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
37996
38207
|
DEFAULT_MAX_REDIRECTS = 5;
|
|
37997
38208
|
FETCH_MAX_REDIRECTS = 20;
|
|
@@ -38233,7 +38444,7 @@ var init_version = __esm({
|
|
|
38233
38444
|
"src/version.ts"() {
|
|
38234
38445
|
"use strict";
|
|
38235
38446
|
PACKAGE_NAME = "office-outlook-mcp";
|
|
38236
|
-
VERSION = "0.7.
|
|
38447
|
+
VERSION = "0.7.1";
|
|
38237
38448
|
}
|
|
38238
38449
|
});
|
|
38239
38450
|
|
|
@@ -50614,7 +50825,7 @@ function dateTimeTimeZone2(value, zone) {
|
|
|
50614
50825
|
}
|
|
50615
50826
|
return { DateTime: value, TimeZone: zone };
|
|
50616
50827
|
}
|
|
50617
|
-
var TIMEOUT_SENTENCE = 'If Outlook does not answer in time
|
|
50828
|
+
var TIMEOUT_SENTENCE = 'If Outlook does not answer in time, the connection drops, or a server error (5xx) comes back after the request was sent, the result has status "unknown": the write may well have gone through, so check before retrying \u2014 never resend blindly.';
|
|
50618
50829
|
function writeOrUnknown2(run, checkWhere) {
|
|
50619
50830
|
return writeOrUnknown(
|
|
50620
50831
|
run,
|
|
@@ -51491,6 +51702,9 @@ function expiry(opts) {
|
|
|
51491
51702
|
return Math.floor((opts?.now ?? Date.now()) + ttl);
|
|
51492
51703
|
}
|
|
51493
51704
|
function toArrayBuffer(view) {
|
|
51705
|
+
const buf = view.buffer;
|
|
51706
|
+
if (buf instanceof ArrayBuffer && view.byteOffset === 0 && view.byteLength === buf.byteLength)
|
|
51707
|
+
return buf;
|
|
51494
51708
|
return view.slice().buffer;
|
|
51495
51709
|
}
|
|
51496
51710
|
function createBlobStore(opts) {
|
|
@@ -51704,6 +51918,7 @@ function buildZip(entries, modifiedAt = new Date(Date.UTC(1980, 0, 1))) {
|
|
|
51704
51918
|
// node_modules/@chrischall/mcp-utils/dist/export/sink.js
|
|
51705
51919
|
var EXPORT_MARKER = ".mcp-export";
|
|
51706
51920
|
var EXPORT_DIR_NAME = /-\d{8}-\d{6}(?:-\d+)?$/;
|
|
51921
|
+
var EXPORT_BLOB_MAX_BYTES = 256 * 1024 * 1024;
|
|
51707
51922
|
var EXPORT_ID = /^[A-Za-z0-9_-]{8,64}$/;
|
|
51708
51923
|
var MAX_PART = 9999;
|
|
51709
51924
|
var MAX_REL_PATH = 1024;
|
|
@@ -51781,14 +51996,17 @@ async function openExportSink(opts) {
|
|
|
51781
51996
|
const part = checkPart(opts.part ?? 1);
|
|
51782
51997
|
const exportId = checkExportId(opts.exportId);
|
|
51783
51998
|
const now = opts.now;
|
|
51999
|
+
if (opts.maxBytes !== void 0 && !(Number.isSafeInteger(opts.maxBytes) && opts.maxBytes > 0)) {
|
|
52000
|
+
throw new TypeError(`openExportSink: maxBytes must be a positive whole number, got ${opts.maxBytes}.`);
|
|
52001
|
+
}
|
|
51784
52002
|
const store = blobStoreFromEnv(env);
|
|
51785
52003
|
if (store)
|
|
51786
52004
|
return openBlobSink(store, exportId, part, opts, now);
|
|
51787
52005
|
if (opts.existingDir !== void 0) {
|
|
51788
|
-
return openDiskSink(resumeDir(opts.existingDir, opts.envVar, env, exportId), exportId, part);
|
|
52006
|
+
return openDiskSink(resumeDir(opts.existingDir, opts.envVar, env, exportId, opts.name), exportId, part);
|
|
51789
52007
|
}
|
|
51790
52008
|
const dir = freshDir(opts, env, now);
|
|
51791
|
-
await writeFileSafe(join10(dir, EXPORT_MARKER), new TextEncoder().encode(JSON.stringify({ exportId })), {
|
|
52009
|
+
await writeFileSafe(join10(dir, EXPORT_MARKER), new TextEncoder().encode(JSON.stringify({ exportId, name: opts.name })), {
|
|
51792
52010
|
allowedRoots: [dir],
|
|
51793
52011
|
mode: 384
|
|
51794
52012
|
});
|
|
@@ -51831,6 +52049,7 @@ function freshDir(opts, env, now) {
|
|
|
51831
52049
|
function notThisExport() {
|
|
51832
52050
|
return badInput2("The export directory to resume was not created by this export.", "Pass the cursor exactly as returned, or start a new export without one.");
|
|
51833
52051
|
}
|
|
52052
|
+
var MAX_MARKER = 4096;
|
|
51834
52053
|
function readMarker(dir) {
|
|
51835
52054
|
let fd;
|
|
51836
52055
|
try {
|
|
@@ -51839,18 +52058,21 @@ function readMarker(dir) {
|
|
|
51839
52058
|
return void 0;
|
|
51840
52059
|
}
|
|
51841
52060
|
try {
|
|
51842
|
-
const buf = Buffer.alloc(
|
|
52061
|
+
const buf = Buffer.alloc(MAX_MARKER);
|
|
51843
52062
|
const n = readSync(fd, buf, 0, buf.length, 0);
|
|
51844
52063
|
const parsed = JSON.parse(buf.subarray(0, n).toString("utf8"));
|
|
51845
52064
|
const id = parsed?.exportId;
|
|
51846
|
-
|
|
52065
|
+
const name = parsed?.name;
|
|
52066
|
+
if (typeof id !== "string")
|
|
52067
|
+
return void 0;
|
|
52068
|
+
return { exportId: id, name: typeof name === "string" ? name : void 0 };
|
|
51847
52069
|
} catch {
|
|
51848
52070
|
return void 0;
|
|
51849
52071
|
} finally {
|
|
51850
52072
|
closeSync4(fd);
|
|
51851
52073
|
}
|
|
51852
52074
|
}
|
|
51853
|
-
function resumeDir(existingDir, envVar, env, exportId) {
|
|
52075
|
+
function resumeDir(existingDir, envVar, env, exportId, name) {
|
|
51854
52076
|
if (typeof existingDir !== "string" || existingDir.length === 0)
|
|
51855
52077
|
throw outsideRoots("export directory", envVar);
|
|
51856
52078
|
const roots = exportAllowedRoots(envVar, env);
|
|
@@ -51876,7 +52098,10 @@ function resumeDir(existingDir, envVar, env, exportId) {
|
|
|
51876
52098
|
} catch {
|
|
51877
52099
|
markerIsFile = false;
|
|
51878
52100
|
}
|
|
51879
|
-
if (!markerIsFile
|
|
52101
|
+
if (!markerIsFile)
|
|
52102
|
+
throw notThisExport();
|
|
52103
|
+
const marker = readMarker(real);
|
|
52104
|
+
if (!marker || marker.exportId !== exportId || marker.name !== name)
|
|
51880
52105
|
throw notThisExport();
|
|
51881
52106
|
return real;
|
|
51882
52107
|
}
|
|
@@ -51930,6 +52155,8 @@ function openBlobSink(store, exportId, part, opts, now) {
|
|
|
51930
52155
|
const signOpts = { ...opts.ttlMs !== void 0 ? { ttlMs: opts.ttlMs } : {} };
|
|
51931
52156
|
store.signGetUrl(key, { ...signOpts, now: now ?? Date.now() });
|
|
51932
52157
|
const entries = /* @__PURE__ */ new Map();
|
|
52158
|
+
const maxBytes = opts.maxBytes ?? EXPORT_BLOB_MAX_BYTES;
|
|
52159
|
+
let held = 0;
|
|
51933
52160
|
let finished = false;
|
|
51934
52161
|
return {
|
|
51935
52162
|
mode: "blob",
|
|
@@ -51942,6 +52169,20 @@ function openBlobSink(store, exportId, part, opts, now) {
|
|
|
51942
52169
|
if (entries.has(relPath) && !o.overwrite)
|
|
51943
52170
|
throw badInput2(`Export file ${relPath} was already written.`);
|
|
51944
52171
|
const bytes = toBytes(data);
|
|
52172
|
+
const replaced = entries.get(relPath)?.bytes.byteLength ?? 0;
|
|
52173
|
+
if (bytes.byteLength > maxBytes) {
|
|
52174
|
+
throw new McpToolError(`Export file ${relPath} alone is ${bytes.byteLength} bytes, over the ${maxBytes}-byte part limit.`, {
|
|
52175
|
+
kind: "too_large",
|
|
52176
|
+
hint: "No export part can hold this file: skip it, or raise the part limit (maxBytes)."
|
|
52177
|
+
});
|
|
52178
|
+
}
|
|
52179
|
+
if (held - replaced + bytes.byteLength > maxBytes) {
|
|
52180
|
+
throw new McpToolError(`This export part would exceed its ${maxBytes}-byte limit with ${relPath}.`, {
|
|
52181
|
+
kind: "too_large",
|
|
52182
|
+
hint: "Finish this part and continue the export in the next one (return the resume cursor)."
|
|
52183
|
+
});
|
|
52184
|
+
}
|
|
52185
|
+
held += bytes.byteLength - replaced;
|
|
51945
52186
|
entries.delete(relPath);
|
|
51946
52187
|
entries.set(relPath, { bytes, compress: shouldCompress(relPath, contentType) });
|
|
51947
52188
|
return { name: relPath, bytes: bytes.byteLength };
|
|
@@ -52138,7 +52379,7 @@ function isoBound(name, raw) {
|
|
|
52138
52379
|
}
|
|
52139
52380
|
return decodeFrom(raw).t;
|
|
52140
52381
|
}
|
|
52141
|
-
var
|
|
52382
|
+
var defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
52142
52383
|
async function with429Retry(fn, sleep3) {
|
|
52143
52384
|
for (let attempt = 0; ; attempt++) {
|
|
52144
52385
|
try {
|
|
@@ -52278,7 +52519,7 @@ function extendSpan(totals, t) {
|
|
|
52278
52519
|
if (!totals.oldest || ms < timeOf(totals.oldest)) totals.oldest = t;
|
|
52279
52520
|
if (!totals.newest || ms > timeOf(totals.newest)) totals.newest = t;
|
|
52280
52521
|
}
|
|
52281
|
-
function
|
|
52522
|
+
function inRange2(received, since, until) {
|
|
52282
52523
|
if (!since && !until) return true;
|
|
52283
52524
|
const t = timeOf(received);
|
|
52284
52525
|
if (Number.isNaN(t)) return false;
|
|
@@ -52658,7 +52899,7 @@ function registerExportTools(server, client2, opts = {}) {
|
|
|
52658
52899
|
const run = {
|
|
52659
52900
|
...opts,
|
|
52660
52901
|
env: opts.env ?? process.env,
|
|
52661
|
-
sleep: opts.sleep ??
|
|
52902
|
+
sleep: opts.sleep ?? defaultSleep,
|
|
52662
52903
|
clock: opts.clock ?? Date.now
|
|
52663
52904
|
};
|
|
52664
52905
|
const pageSize = Math.min(Math.max(1, opts.pageSize ?? MAX_TOP2), MAX_TOP2);
|
|
@@ -52745,7 +52986,7 @@ function registerExportTools(server, client2, opts = {}) {
|
|
|
52745
52986
|
sleep3
|
|
52746
52987
|
),
|
|
52747
52988
|
(link2) => with429Retry(() => client2.getAbsolute(link2, { text: true }), sleep3),
|
|
52748
|
-
(m) =>
|
|
52989
|
+
(m) => inRange2(m.ReceivedDateTime, since, until)
|
|
52749
52990
|
);
|
|
52750
52991
|
};
|
|
52751
52992
|
return runExport(client2, run, input2, {
|
package/dist/tools/writes.js
CHANGED
|
@@ -68,7 +68,7 @@ function dateTimeTimeZone(value, zone) {
|
|
|
68
68
|
* Tool-description sentence for a write whose timeout leaves the outcome
|
|
69
69
|
* unknown. Kept next to {@link unknownOutcome} so the two cannot drift.
|
|
70
70
|
*/
|
|
71
|
-
const TIMEOUT_SENTENCE = 'If Outlook does not answer in time
|
|
71
|
+
const TIMEOUT_SENTENCE = 'If Outlook does not answer in time, the connection drops, or a server error (5xx) comes back after the request was sent, the result has status "unknown": the write may well have gone through, so check before retrying — never resend blindly.';
|
|
72
72
|
/**
|
|
73
73
|
* Run a non-idempotent write; a timeout or dropped connection after the
|
|
74
74
|
* request was sent (mcp-utils' WriteOutcomeUnknownError) becomes a non-error
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrischall/office-outlook-mcp",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"mcpName": "io.github.chrischall/office-outlook-mcp",
|
|
5
5
|
"description": "Outlook / Microsoft 365 MCP server for Claude — developed and maintained by AI (Claude Code)",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"typecheck": "tsc -p tsconfig.check.json"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@chrischall/mcp-utils": "^3.3.
|
|
48
|
+
"@chrischall/mcp-utils": "^3.3.1",
|
|
49
49
|
"@fetchproxy/server": "^3.6.2",
|
|
50
50
|
"@modelcontextprotocol/server": "^2.3.0",
|
|
51
51
|
"dotenv": "^18.0.1",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/office-outlook-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.7.
|
|
9
|
+
"version": "0.7.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@chrischall/office-outlook-mcp",
|
|
14
|
-
"version": "0.7.
|
|
14
|
+
"version": "0.7.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|