@chrischall/office-outlook-mcp 0.10.0 → 0.10.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 +282 -37
- package/dist/version.js +1 -1
- package/package.json +10 -10
- 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.10.
|
|
10
|
+
"version": "0.10.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.10.
|
|
18
|
+
"version": "0.10.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.10.
|
|
4
|
+
"version": "0.10.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
|
@@ -39293,7 +39293,7 @@ var init_version = __esm({
|
|
|
39293
39293
|
"src/version.ts"() {
|
|
39294
39294
|
"use strict";
|
|
39295
39295
|
PACKAGE_NAME = "office-outlook-mcp";
|
|
39296
|
-
VERSION = "0.10.
|
|
39296
|
+
VERSION = "0.10.1";
|
|
39297
39297
|
}
|
|
39298
39298
|
});
|
|
39299
39299
|
|
|
@@ -39673,6 +39673,38 @@ var init_capability_availability = __esm({
|
|
|
39673
39673
|
}
|
|
39674
39674
|
});
|
|
39675
39675
|
|
|
39676
|
+
// node_modules/@fetchproxy/protocol/dist/binary-fetch.js
|
|
39677
|
+
function parseResponseTooLarge(error62) {
|
|
39678
|
+
const declared = TOO_LARGE_DECLARED_RE.exec(error62);
|
|
39679
|
+
if (declared)
|
|
39680
|
+
return { limitBytes: Number(declared[2]), declaredBytes: Number(declared[1]) };
|
|
39681
|
+
const streamed = TOO_LARGE_STREAMED_RE.exec(error62);
|
|
39682
|
+
if (streamed)
|
|
39683
|
+
return { limitBytes: Number(streamed[1]), declaredBytes: null };
|
|
39684
|
+
return null;
|
|
39685
|
+
}
|
|
39686
|
+
function isBase64Body(s) {
|
|
39687
|
+
return s.length % 4 === 0 && BASE64_RE.test(s);
|
|
39688
|
+
}
|
|
39689
|
+
var FETCH_RESPONSE_TYPE_BASE64, EXTENSION_FEATURE_FETCH_BASE64, KNOWN_EXTENSION_FEATURES, MAX_EXTENSION_FEATURES, MAX_EXTENSION_FEATURE_LENGTH, HOSTED_RELAY_MESSAGE_BYTES, MAX_BINARY_RESPONSE_BYTES, RESPONSE_TOO_LARGE_CODE, TOO_LARGE_DECLARED_RE, TOO_LARGE_STREAMED_RE, BASE64_RE;
|
|
39690
|
+
var init_binary_fetch = __esm({
|
|
39691
|
+
"node_modules/@fetchproxy/protocol/dist/binary-fetch.js"() {
|
|
39692
|
+
FETCH_RESPONSE_TYPE_BASE64 = "base64";
|
|
39693
|
+
EXTENSION_FEATURE_FETCH_BASE64 = "fetch_base64";
|
|
39694
|
+
KNOWN_EXTENSION_FEATURES = /* @__PURE__ */ new Set([
|
|
39695
|
+
EXTENSION_FEATURE_FETCH_BASE64
|
|
39696
|
+
]);
|
|
39697
|
+
MAX_EXTENSION_FEATURES = 32;
|
|
39698
|
+
MAX_EXTENSION_FEATURE_LENGTH = 64;
|
|
39699
|
+
HOSTED_RELAY_MESSAGE_BYTES = 32 * 1024 * 1024;
|
|
39700
|
+
MAX_BINARY_RESPONSE_BYTES = 16 * 1024 * 1024;
|
|
39701
|
+
RESPONSE_TOO_LARGE_CODE = "response_too_large";
|
|
39702
|
+
TOO_LARGE_DECLARED_RE = /^response body too large: content-length (\d{1,16}) exceeds the (\d{1,16})-byte binary cap/;
|
|
39703
|
+
TOO_LARGE_STREAMED_RE = /^response body too large: more than the (\d{1,16})-byte binary cap was received/;
|
|
39704
|
+
BASE64_RE = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
39705
|
+
}
|
|
39706
|
+
});
|
|
39707
|
+
|
|
39676
39708
|
// node_modules/@fetchproxy/protocol/dist/json-pointer.js
|
|
39677
39709
|
function matchesDeclaredKey(requested, declared) {
|
|
39678
39710
|
for (const decl of declared) {
|
|
@@ -39884,7 +39916,7 @@ function assertString(x, label) {
|
|
|
39884
39916
|
}
|
|
39885
39917
|
function assertBase64(x, label) {
|
|
39886
39918
|
assertString(x, label);
|
|
39887
|
-
if (!
|
|
39919
|
+
if (!BASE64_RE2.test(x))
|
|
39888
39920
|
throw new ProtocolError3(`${label}: invalid base64`);
|
|
39889
39921
|
}
|
|
39890
39922
|
function base64ByteLength(s) {
|
|
@@ -40288,6 +40320,17 @@ function validateFrame(raw) {
|
|
|
40288
40320
|
}
|
|
40289
40321
|
throw new ProtocolError3(`unknown frame type: ${String(t)}`);
|
|
40290
40322
|
}
|
|
40323
|
+
function assertTabDomains(value, domains, label) {
|
|
40324
|
+
if (!Array.isArray(value))
|
|
40325
|
+
throw new ProtocolError3(`${label}: expected array`);
|
|
40326
|
+
if (value.length === 0)
|
|
40327
|
+
throw new ProtocolError3(`${label}: must be non-empty`);
|
|
40328
|
+
for (const d of value) {
|
|
40329
|
+
if (typeof d !== "string" || !domains.includes(d)) {
|
|
40330
|
+
throw new ProtocolError3(`${label}: ${JSON.stringify(d)} is not one of the declared domains [${domains.join(", ")}]`);
|
|
40331
|
+
}
|
|
40332
|
+
}
|
|
40333
|
+
}
|
|
40291
40334
|
function validateHello(raw) {
|
|
40292
40335
|
if (raw.protocolVersion !== PROTOCOL_VERSION) {
|
|
40293
40336
|
throw new ProtocolError3(`hello.protocolVersion: must be ${PROTOCOL_VERSION}`);
|
|
@@ -40364,6 +40407,9 @@ function validateHello(raw) {
|
|
|
40364
40407
|
}
|
|
40365
40408
|
if (raw.accepts !== void 0)
|
|
40366
40409
|
assertAcceptsList(raw.accepts);
|
|
40410
|
+
if (raw.tabDomains !== void 0) {
|
|
40411
|
+
assertTabDomains(raw.tabDomains, raw.domains, "hello.tabDomains");
|
|
40412
|
+
}
|
|
40367
40413
|
if (raw.graphqlOps !== void 0) {
|
|
40368
40414
|
assertGraphqlOpsArray(raw.graphqlOps, "hello.graphqlOps");
|
|
40369
40415
|
}
|
|
@@ -40390,6 +40436,8 @@ function validateHello(raw) {
|
|
|
40390
40436
|
if (raw.unavailableCapabilities !== void 0) {
|
|
40391
40437
|
assertUnavailableCapabilities(raw.unavailableCapabilities);
|
|
40392
40438
|
}
|
|
40439
|
+
if (raw.features !== void 0)
|
|
40440
|
+
assertExtensionFeatures(raw.features);
|
|
40393
40441
|
return raw;
|
|
40394
40442
|
}
|
|
40395
40443
|
throw new ProtocolError3(`hello.role: must be 'server' or 'extension', got ${String(role)}`);
|
|
@@ -40454,6 +40502,22 @@ function assertAcceptsList(accepts) {
|
|
|
40454
40502
|
}
|
|
40455
40503
|
}
|
|
40456
40504
|
}
|
|
40505
|
+
function assertExtensionFeatures(list) {
|
|
40506
|
+
const label = "hello.features";
|
|
40507
|
+
if (!Array.isArray(list))
|
|
40508
|
+
throw new ProtocolError3(`${label}: expected array`);
|
|
40509
|
+
if (list.length > MAX_EXTENSION_FEATURES) {
|
|
40510
|
+
throw new ProtocolError3(`${label}: at most ${MAX_EXTENSION_FEATURES} entries, got ${list.length}`);
|
|
40511
|
+
}
|
|
40512
|
+
for (const f of list) {
|
|
40513
|
+
if (typeof f !== "string") {
|
|
40514
|
+
throw new ProtocolError3(`${label}: entry must be string, got ${typeof f}`);
|
|
40515
|
+
}
|
|
40516
|
+
if (f.length < 1 || f.length > MAX_EXTENSION_FEATURE_LENGTH) {
|
|
40517
|
+
throw new ProtocolError3(`${label}: entry must be 1-${MAX_EXTENSION_FEATURE_LENGTH} characters, got ${f.length}`);
|
|
40518
|
+
}
|
|
40519
|
+
}
|
|
40520
|
+
}
|
|
40457
40521
|
function assertUnavailableCapabilities(list) {
|
|
40458
40522
|
const label = "hello.unavailableCapabilities";
|
|
40459
40523
|
if (!Array.isArray(list))
|
|
@@ -40657,6 +40721,11 @@ function validateInnerRequest(raw) {
|
|
|
40657
40721
|
throw new ProtocolError3("inner.init.credentials: must be 'include' or 'omit'");
|
|
40658
40722
|
}
|
|
40659
40723
|
}
|
|
40724
|
+
if (raw.init.responseType !== void 0) {
|
|
40725
|
+
if (raw.init.responseType !== FETCH_RESPONSE_TYPE_BASE64) {
|
|
40726
|
+
throw new ProtocolError3("inner.init.responseType: must be 'base64' when present");
|
|
40727
|
+
}
|
|
40728
|
+
}
|
|
40660
40729
|
return raw;
|
|
40661
40730
|
}
|
|
40662
40731
|
if (raw.op === "read_cookies") {
|
|
@@ -40961,6 +41030,16 @@ function validateInnerResponse(raw) {
|
|
|
40961
41030
|
assertPositiveInt(raw.status, "inner.status");
|
|
40962
41031
|
assertString(raw.url, "inner.url");
|
|
40963
41032
|
assertString(raw.body, "inner.body");
|
|
41033
|
+
if (raw.bodyEncoding !== void 0) {
|
|
41034
|
+
if (raw.bodyEncoding !== "base64") {
|
|
41035
|
+
throw new ProtocolError3("inner.bodyEncoding: must be 'base64' when present");
|
|
41036
|
+
}
|
|
41037
|
+
if (!isBase64Body(raw.body)) {
|
|
41038
|
+
throw new ProtocolError3("inner.body: not standard padded base64 under bodyEncoding base64");
|
|
41039
|
+
}
|
|
41040
|
+
}
|
|
41041
|
+
if (raw.headers !== void 0)
|
|
41042
|
+
assertStringMap(raw.headers, "inner.headers");
|
|
40964
41043
|
return raw;
|
|
40965
41044
|
}
|
|
40966
41045
|
if (op === "read_cookies") {
|
|
@@ -41079,11 +41158,12 @@ function validateInnerResponse(raw) {
|
|
|
41079
41158
|
}
|
|
41080
41159
|
throw new ProtocolError3(`inner.ok: must be boolean, got ${typeof raw.ok}`);
|
|
41081
41160
|
}
|
|
41082
|
-
var ProtocolError3, FORBIDDEN_KEYS,
|
|
41161
|
+
var ProtocolError3, FORBIDDEN_KEYS, BASE64_RE2, SCOPE_KEY_RE, SCOPE_KEY_GLOB_RE, HEADER_NAME_RE, HOSTNAME_RE, CAPTURE_PATH_RE, DOM_SELECTOR_RE, DOM_ATTRIBUTE_RE, GRAPHQL_OP_NAME_RE, PAIR_CODE_RE, DISPLAY_FORBIDDEN_RE, ACCOUNT_KEY_FIELDS, ACCOUNT_ATTEST_FIELDS, TYPE_ONLY_FIELDS, BRIDGE_ROLE_FIELDS, BRIDGE_ROLE_SERVING_FIELDS, KNOWN_RESPONSE_OPS;
|
|
41083
41162
|
var init_validate = __esm({
|
|
41084
41163
|
"node_modules/@fetchproxy/protocol/dist/validate.js"() {
|
|
41085
41164
|
init_frames();
|
|
41086
41165
|
init_capability_availability();
|
|
41166
|
+
init_binary_fetch();
|
|
41087
41167
|
init_mcp_id();
|
|
41088
41168
|
init_account_attest();
|
|
41089
41169
|
init_json_pointer();
|
|
@@ -41096,7 +41176,7 @@ var init_validate = __esm({
|
|
|
41096
41176
|
}
|
|
41097
41177
|
};
|
|
41098
41178
|
FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
41099
|
-
|
|
41179
|
+
BASE64_RE2 = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
41100
41180
|
SCOPE_KEY_RE = /^[A-Za-z0-9_.\-]{1,256}$/;
|
|
41101
41181
|
SCOPE_KEY_GLOB_RE = /^[A-Za-z0-9_.\-]{1,256}\*?$/;
|
|
41102
41182
|
HEADER_NAME_RE = /^[A-Za-z0-9_\-]{1,128}$/;
|
|
@@ -41260,6 +41340,7 @@ var init_dist3 = __esm({
|
|
|
41260
41340
|
init_account_attest();
|
|
41261
41341
|
init_awaiting_approval();
|
|
41262
41342
|
init_capability_availability();
|
|
41343
|
+
init_binary_fetch();
|
|
41263
41344
|
init_validate();
|
|
41264
41345
|
init_room_frames();
|
|
41265
41346
|
init_crypto();
|
|
@@ -41283,7 +41364,30 @@ function sessionInfoFromHello(hello) {
|
|
|
41283
41364
|
known.add(c);
|
|
41284
41365
|
}
|
|
41285
41366
|
}
|
|
41286
|
-
|
|
41367
|
+
const features = /* @__PURE__ */ new Set();
|
|
41368
|
+
const rawFeatures = hello.features;
|
|
41369
|
+
if (Array.isArray(rawFeatures)) {
|
|
41370
|
+
for (const f of rawFeatures) {
|
|
41371
|
+
if (typeof f === "string" && KNOWN_EXTENSION_FEATURES.has(f))
|
|
41372
|
+
features.add(f);
|
|
41373
|
+
}
|
|
41374
|
+
}
|
|
41375
|
+
return {
|
|
41376
|
+
platform: hello.platform,
|
|
41377
|
+
unavailableCapabilities: [...known].sort(),
|
|
41378
|
+
features: [...features].sort()
|
|
41379
|
+
};
|
|
41380
|
+
}
|
|
41381
|
+
function featureForRequest(inner) {
|
|
41382
|
+
if (inner.type !== "request" || inner.op !== "fetch")
|
|
41383
|
+
return null;
|
|
41384
|
+
return inner.init.responseType === "base64" ? EXTENSION_FEATURE_FETCH_BASE64 : null;
|
|
41385
|
+
}
|
|
41386
|
+
function missingFeatureFor(inner, info) {
|
|
41387
|
+
const feature = featureForRequest(inner);
|
|
41388
|
+
if (feature === null || info === null)
|
|
41389
|
+
return null;
|
|
41390
|
+
return info.features.includes(feature) ? null : feature;
|
|
41287
41391
|
}
|
|
41288
41392
|
function capabilitiesForRequest(inner) {
|
|
41289
41393
|
if (inner.type !== "request")
|
|
@@ -45113,6 +45217,8 @@ async function buildServerHello(opts) {
|
|
|
45113
45217
|
};
|
|
45114
45218
|
if (opts.accepts && opts.accepts.length > 0)
|
|
45115
45219
|
hello.accepts = [...opts.accepts];
|
|
45220
|
+
if (opts.tabDomains && opts.tabDomains.length > 0)
|
|
45221
|
+
hello.tabDomains = [...opts.tabDomains];
|
|
45116
45222
|
if (opts.cookieKeys && opts.cookieKeys.length > 0) {
|
|
45117
45223
|
hello.cookieKeys = [...opts.cookieKeys];
|
|
45118
45224
|
}
|
|
@@ -45950,7 +46056,8 @@ async function startHost(opts) {
|
|
|
45950
46056
|
sessionStoragePointers: opts.ownSessionStoragePointers,
|
|
45951
46057
|
domSelectors: opts.ownDomSelectors,
|
|
45952
46058
|
domListSelectors: opts.ownDomListSelectors,
|
|
45953
|
-
graphqlOps: opts.ownGraphqlOps
|
|
46059
|
+
graphqlOps: opts.ownGraphqlOps,
|
|
46060
|
+
tabDomains: opts.ownTabDomains
|
|
45954
46061
|
};
|
|
45955
46062
|
const generateSessionKeypair = opts.generateSessionKeypair ?? generateX25519;
|
|
45956
46063
|
let extensionWs = null;
|
|
@@ -46536,6 +46643,7 @@ async function startPeer(opts) {
|
|
|
46536
46643
|
localStoragePointers: opts.localStoragePointers,
|
|
46537
46644
|
sessionStoragePointers: opts.sessionStoragePointers,
|
|
46538
46645
|
graphqlOps: opts.graphqlOps,
|
|
46646
|
+
tabDomains: opts.tabDomains,
|
|
46539
46647
|
// 2.5.0: let a host ≥2.5.0 tell us when the extension leaves, so
|
|
46540
46648
|
// `extensionConnected()` / `sessionLinked()` can go back to false.
|
|
46541
46649
|
// 2.6.0: `hello-rejected` for the same reason, from the extension.
|
|
@@ -46914,6 +47022,8 @@ var init_peer = __esm({
|
|
|
46914
47022
|
function classifyFetchError(error62, code2) {
|
|
46915
47023
|
if (code2 === CAPABILITY_UNAVAILABLE_CODE)
|
|
46916
47024
|
return "capability_unavailable";
|
|
47025
|
+
if (code2 === RESPONSE_TOO_LARGE_CODE)
|
|
47026
|
+
return "body_too_large";
|
|
46917
47027
|
if (/^(in-page )?fetch threw:/.test(error62)) {
|
|
46918
47028
|
return "tab_fetch_failed";
|
|
46919
47029
|
}
|
|
@@ -47013,6 +47123,13 @@ function protocolErrorFrom(error62, op, response) {
|
|
|
47013
47123
|
platform: unavailable?.platform ?? null
|
|
47014
47124
|
});
|
|
47015
47125
|
}
|
|
47126
|
+
const tooLarge = parseResponseTooLarge(error62);
|
|
47127
|
+
if (tooLarge !== null || response?.code === RESPONSE_TOO_LARGE_CODE) {
|
|
47128
|
+
return new FetchproxyResponseTooLargeError(error62, {
|
|
47129
|
+
limitBytes: tooLarge?.limitBytes ?? null,
|
|
47130
|
+
declaredBytes: tooLarge?.declaredBytes ?? null
|
|
47131
|
+
});
|
|
47132
|
+
}
|
|
47016
47133
|
if (error62 === "timeout")
|
|
47017
47134
|
return new FetchproxyWaitedError(error62, op);
|
|
47018
47135
|
if (SCOPE_REJECTION.test(error62))
|
|
@@ -47047,6 +47164,13 @@ function assertSubdomainLabel(label) {
|
|
|
47047
47164
|
throw new Error(`FetchproxyServer: subdomain must be a DNS label like "www" or "api" (or dot-separated like "auth.api"), got ${JSON.stringify(label)}`);
|
|
47048
47165
|
}
|
|
47049
47166
|
}
|
|
47167
|
+
function assertExpectedStatus(response, expected, asHttp = () => response) {
|
|
47168
|
+
if (expected === void 0)
|
|
47169
|
+
return;
|
|
47170
|
+
const matched = Array.isArray(expected) ? expected.includes(response.status) : response.status === expected;
|
|
47171
|
+
if (!matched)
|
|
47172
|
+
throw new FetchproxyHttpError(asHttp());
|
|
47173
|
+
}
|
|
47050
47174
|
function assertUrlInDomains(field, url2, domains) {
|
|
47051
47175
|
let parsed;
|
|
47052
47176
|
try {
|
|
@@ -47091,7 +47215,7 @@ function isResendableRequest(inner) {
|
|
|
47091
47215
|
return true;
|
|
47092
47216
|
}
|
|
47093
47217
|
}
|
|
47094
|
-
var FetchproxyProtocolError, FetchproxyHttpError, FetchproxyBridgeDownError, FetchproxyHintedError, FetchproxyScopeError, FetchproxyNoTabError, FetchproxyTabOpeningError, FetchproxyWaitedError, FetchproxyCapabilityUnavailableError, SCOPE_REJECTION, NO_TAB_REJECTION, TAB_OPENING_REJECTION, VERB_DEADLINE_GRACE_MS, FetchproxyTimeoutError, TIMEOUT_NOT_RESENT_NOTE, SUBDOMAIN_LABEL_RE, DEFAULT_JSON_OK_STATUSES, TIMEOUT_RETRY_SAFE_METHODS, FetchproxyServer;
|
|
47218
|
+
var FetchproxyProtocolError, FetchproxyHttpError, FetchproxyBridgeDownError, FetchproxyHintedError, FetchproxyScopeError, FetchproxyNoTabError, FetchproxyTabOpeningError, FetchproxyWaitedError, FetchproxyCapabilityUnavailableError, FetchproxyExtensionUpdateRequiredError, FetchproxyResponseTooLargeError, SCOPE_REJECTION, NO_TAB_REJECTION, TAB_OPENING_REJECTION, VERB_DEADLINE_GRACE_MS, FetchproxyTimeoutError, TIMEOUT_NOT_RESENT_NOTE, SUBDOMAIN_LABEL_RE, DEFAULT_JSON_OK_STATUSES, TIMEOUT_RETRY_SAFE_METHODS, FetchproxyServer;
|
|
47095
47219
|
var init_ws_server = __esm({
|
|
47096
47220
|
"node_modules/@fetchproxy/server/dist/ws-server.js"() {
|
|
47097
47221
|
init_dist3();
|
|
@@ -47194,6 +47318,28 @@ var init_ws_server = __esm({
|
|
|
47194
47318
|
this.platform = info.platform;
|
|
47195
47319
|
}
|
|
47196
47320
|
};
|
|
47321
|
+
FetchproxyExtensionUpdateRequiredError = class extends FetchproxyHintedError {
|
|
47322
|
+
/** The feature the extension lacks (`'fetch_base64'`). */
|
|
47323
|
+
feature;
|
|
47324
|
+
constructor(originalError, info) {
|
|
47325
|
+
super(originalError, `this MCP needs the browser extension to support "${info.feature}" (binary downloads through the bridge), and the ContextMint Bridge build it is paired with does not. Update ContextMint Bridge (Chrome Web Store / App Store, or rebuild a sideloaded copy and reload it), then retry. Nothing is wrong with the MCP or your pairing, and re-pairing will not change it.`);
|
|
47326
|
+
this.name = "FetchproxyExtensionUpdateRequiredError";
|
|
47327
|
+
this.feature = info.feature;
|
|
47328
|
+
}
|
|
47329
|
+
};
|
|
47330
|
+
FetchproxyResponseTooLargeError = class extends FetchproxyHintedError {
|
|
47331
|
+
/** The cap the extension enforced, in bytes, when it said; else `null`. */
|
|
47332
|
+
limitBytes;
|
|
47333
|
+
/** The response's `content-length`, when the refusal came from it; else `null`. */
|
|
47334
|
+
declaredBytes;
|
|
47335
|
+
constructor(originalError, info) {
|
|
47336
|
+
const cap = info.limitBytes ?? MAX_BINARY_RESPONSE_BYTES;
|
|
47337
|
+
super(originalError, `the file is larger than the ${cap}-byte cap one bridge response can carry, so the extension refused it rather than send a frame the bridge cannot deliver. This is not a version or pairing problem: fetch a smaller rendition if the site offers one, or download it directly in the browser.`);
|
|
47338
|
+
this.name = "FetchproxyResponseTooLargeError";
|
|
47339
|
+
this.limitBytes = info.limitBytes;
|
|
47340
|
+
this.declaredBytes = info.declaredBytes;
|
|
47341
|
+
}
|
|
47342
|
+
};
|
|
47197
47343
|
SCOPE_REJECTION = /not in declared/;
|
|
47198
47344
|
NO_TAB_REJECTION = /no tab matching (?!.*(content script loaded|one is still opening))/;
|
|
47199
47345
|
TAB_OPENING_REJECTION = /no tab matching .*one is still opening/;
|
|
@@ -47360,6 +47506,9 @@ var init_ws_server = __esm({
|
|
|
47360
47506
|
throw new Error(`FetchproxyServer: opts.domains entry ${JSON.stringify(d)} is a public suffix \u2014 declare a registrable domain (e.g. "example.${d}"), not the suffix every site under it shares`);
|
|
47361
47507
|
}
|
|
47362
47508
|
}
|
|
47509
|
+
if (opts.tabDomains !== void 0) {
|
|
47510
|
+
assertTabDomains(opts.tabDomains, opts.domains, "FetchproxyServer: opts.tabDomains");
|
|
47511
|
+
}
|
|
47363
47512
|
let capabilities;
|
|
47364
47513
|
if (opts.capabilities === void 0) {
|
|
47365
47514
|
capabilities = ["fetch"];
|
|
@@ -47430,6 +47579,7 @@ var init_ws_server = __esm({
|
|
|
47430
47579
|
name: d.name,
|
|
47431
47580
|
operationName: d.operationName
|
|
47432
47581
|
})),
|
|
47582
|
+
...opts.tabDomains !== void 0 ? { tabDomains: [...opts.tabDomains] } : {},
|
|
47433
47583
|
// 0.8.0+: timer + lazy-revive default to ON. Every realty MCP
|
|
47434
47584
|
// adapter was about to set these to the same numbers anyway; the
|
|
47435
47585
|
// back-door is `0` (explicit opt-out) if a caller genuinely wants
|
|
@@ -47559,6 +47709,7 @@ var init_ws_server = __esm({
|
|
|
47559
47709
|
ownDomSelectors: this.opts.domSelectors,
|
|
47560
47710
|
ownDomListSelectors: this.opts.domListSelectors,
|
|
47561
47711
|
ownGraphqlOps: this.opts.graphqlOps,
|
|
47712
|
+
ownTabDomains: this.opts.tabDomains,
|
|
47562
47713
|
onPairCode: this.opts.onPairCode,
|
|
47563
47714
|
extensionTrust: this.extensionTrust()
|
|
47564
47715
|
});
|
|
@@ -47592,6 +47743,7 @@ var init_ws_server = __esm({
|
|
|
47592
47743
|
domSelectors: this.opts.domSelectors,
|
|
47593
47744
|
domListSelectors: this.opts.domListSelectors,
|
|
47594
47745
|
graphqlOps: this.opts.graphqlOps,
|
|
47746
|
+
tabDomains: this.opts.tabDomains,
|
|
47595
47747
|
extensionTrust: this.extensionTrust(),
|
|
47596
47748
|
requireExtensionIdentity: this.opts.requireExtensionIdentity
|
|
47597
47749
|
});
|
|
@@ -47876,6 +48028,15 @@ var init_ws_server = __esm({
|
|
|
47876
48028
|
cause: err
|
|
47877
48029
|
};
|
|
47878
48030
|
}
|
|
48031
|
+
if (err instanceof FetchproxyExtensionUpdateRequiredError) {
|
|
48032
|
+
return {
|
|
48033
|
+
ok: false,
|
|
48034
|
+
error: err.originalError,
|
|
48035
|
+
kind: "extension_update_required",
|
|
48036
|
+
retryAttempted: false,
|
|
48037
|
+
cause: err
|
|
48038
|
+
};
|
|
48039
|
+
}
|
|
47879
48040
|
return {
|
|
47880
48041
|
ok: false,
|
|
47881
48042
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -48022,7 +48183,10 @@ var init_ws_server = __esm({
|
|
|
48022
48183
|
if (result.kind === "capability_unavailable") {
|
|
48023
48184
|
return protocolErrorFrom(result.error, void 0, { code: CAPABILITY_UNAVAILABLE_CODE, op });
|
|
48024
48185
|
}
|
|
48025
|
-
|
|
48186
|
+
if (result.kind === "extension_update_required" && result.cause instanceof FetchproxyExtensionUpdateRequiredError) {
|
|
48187
|
+
return result.cause;
|
|
48188
|
+
}
|
|
48189
|
+
return protocolErrorFrom(result.error, void 0, result.code !== void 0 ? { code: result.code, op } : void 0);
|
|
48026
48190
|
}
|
|
48027
48191
|
/**
|
|
48028
48192
|
* Convenience wrapper around `fetch()`. Builds the URL from a path
|
|
@@ -48042,6 +48206,88 @@ var init_ws_server = __esm({
|
|
|
48042
48206
|
* the declared domains exactly.
|
|
48043
48207
|
*/
|
|
48044
48208
|
async request(method, path2, opts = {}) {
|
|
48209
|
+
const init = this.resolveRequestInit("request", method, path2, opts);
|
|
48210
|
+
const result = await this.fetch(init, opts.retryOnTimeout !== void 0 ? { retryOnTimeout: opts.retryOnTimeout } : {});
|
|
48211
|
+
if (!result.ok)
|
|
48212
|
+
this.throwFetchFailure(result, init.url, method, opts.retryOnTimeout);
|
|
48213
|
+
const response = {
|
|
48214
|
+
status: result.status,
|
|
48215
|
+
body: result.body,
|
|
48216
|
+
url: result.url
|
|
48217
|
+
};
|
|
48218
|
+
assertExpectedStatus(response, opts.expectStatus);
|
|
48219
|
+
return response;
|
|
48220
|
+
}
|
|
48221
|
+
/**
|
|
48222
|
+
* #460: like `request()`, but the response body comes back as BYTES,
|
|
48223
|
+
* intact — a PDF, an office file, an image — together with the relayed
|
|
48224
|
+
* `content-type` / `content-length` / `content-disposition` headers and the
|
|
48225
|
+
* final URL after redirects.
|
|
48226
|
+
*
|
|
48227
|
+
* The extension runs it from its background worker rather than a tab, so a
|
|
48228
|
+
* file host that sends no CORS headers is still readable, and it follows
|
|
48229
|
+
* redirects. Both the request URL and the FINAL URL must be inside the
|
|
48230
|
+
* declared `domains` — the extension enforces that, and so does this method
|
|
48231
|
+
* on the answer. To read a signed file host, declare it.
|
|
48232
|
+
*
|
|
48233
|
+
* Bodies are capped at `MAX_BINARY_RESPONSE_BYTES` (16 MiB): over it the
|
|
48234
|
+
* extension refuses with `FetchproxyResponseTooLargeError`. An extension
|
|
48235
|
+
* that predates binary fetch is refused with
|
|
48236
|
+
* `FetchproxyExtensionUpdateRequiredError` — locally when its hello says so,
|
|
48237
|
+
* and on the answer when it replied in text anyway.
|
|
48238
|
+
*/
|
|
48239
|
+
async requestBytes(method, path2, opts = {}) {
|
|
48240
|
+
const init = {
|
|
48241
|
+
...this.resolveRequestInit("requestBytes", method, path2, opts),
|
|
48242
|
+
responseType: "base64"
|
|
48243
|
+
};
|
|
48244
|
+
const result = await this.fetch(init, opts.retryOnTimeout !== void 0 ? { retryOnTimeout: opts.retryOnTimeout } : {});
|
|
48245
|
+
if (!result.ok)
|
|
48246
|
+
this.throwFetchFailure(result, init.url, method, opts.retryOnTimeout);
|
|
48247
|
+
if (result.bodyEncoding !== "base64") {
|
|
48248
|
+
throw new FetchproxyExtensionUpdateRequiredError("the paired ContextMint Bridge extension answered a binary request as text", { feature: EXTENSION_FEATURE_FETCH_BASE64 });
|
|
48249
|
+
}
|
|
48250
|
+
try {
|
|
48251
|
+
assertUrlInDomains("requestBytes final url", result.url, this.opts.domains);
|
|
48252
|
+
} catch (err) {
|
|
48253
|
+
throw new FetchproxyProtocolError(err.message);
|
|
48254
|
+
}
|
|
48255
|
+
if (!isBase64Body(result.body)) {
|
|
48256
|
+
throw new FetchproxyProtocolError("requestBytes: the extension sent a body that is not base64");
|
|
48257
|
+
}
|
|
48258
|
+
const decoded = Buffer.from(result.body, "base64");
|
|
48259
|
+
const response = {
|
|
48260
|
+
status: result.status,
|
|
48261
|
+
url: result.url,
|
|
48262
|
+
headers: { ...result.headers ?? {} },
|
|
48263
|
+
bytes: new Uint8Array(decoded.buffer, decoded.byteOffset, decoded.byteLength)
|
|
48264
|
+
};
|
|
48265
|
+
assertExpectedStatus(response, opts.expectStatus, () => ({
|
|
48266
|
+
status: response.status,
|
|
48267
|
+
url: response.url,
|
|
48268
|
+
// FetchproxyHttpError carries an HttpResponse; a binary body has no
|
|
48269
|
+
// honest text form, so the bytes stay on the BinaryResponse.
|
|
48270
|
+
body: ""
|
|
48271
|
+
}));
|
|
48272
|
+
return response;
|
|
48273
|
+
}
|
|
48274
|
+
/** #460: `requestBytes('GET', path, opts)`. */
|
|
48275
|
+
getBytes(path2, opts = {}) {
|
|
48276
|
+
return this.requestBytes("GET", path2, opts);
|
|
48277
|
+
}
|
|
48278
|
+
/**
|
|
48279
|
+
* Resolve `path` + options into the wire `FetchInit` — URL building, the
|
|
48280
|
+
* declared-domain guard, the relay tab. Shared by `request()` and
|
|
48281
|
+
* `requestBytes()` so the two can never disagree about which URLs are
|
|
48282
|
+
* reachable.
|
|
48283
|
+
*
|
|
48284
|
+
* Path resolution:
|
|
48285
|
+
* - Absolute URL (`https://...`) → used as-is (still guarded against
|
|
48286
|
+
* leaving the declared domain set).
|
|
48287
|
+
* - Relative path → joined with `https://${subdomain}.${baseDomain}`
|
|
48288
|
+
* (or `https://${baseDomain}` if no subdomain is given).
|
|
48289
|
+
*/
|
|
48290
|
+
resolveRequestInit(caller, method, path2, opts) {
|
|
48045
48291
|
if (opts.subdomain !== void 0)
|
|
48046
48292
|
assertSubdomainLabel(opts.subdomain);
|
|
48047
48293
|
const baseDomain = this.resolveBaseDomain(opts.domain);
|
|
@@ -48051,24 +48297,24 @@ var init_ws_server = __esm({
|
|
|
48051
48297
|
try {
|
|
48052
48298
|
host = new URL(path2).host;
|
|
48053
48299
|
} catch {
|
|
48054
|
-
throw new Error(`FetchproxyServer
|
|
48300
|
+
throw new Error(`FetchproxyServer.${caller}: absolute path is not a valid URL: ${JSON.stringify(path2)}`);
|
|
48055
48301
|
}
|
|
48056
48302
|
} else {
|
|
48057
48303
|
host = opts.subdomain ? `${opts.subdomain}.${baseDomain}` : baseDomain;
|
|
48058
48304
|
}
|
|
48059
48305
|
const url2 = isAbsolute6 ? path2 : `https://${host}${path2}`;
|
|
48060
|
-
assertUrlInDomains(
|
|
48306
|
+
assertUrlInDomains(`${caller} url`, url2, this.opts.domains);
|
|
48061
48307
|
let tabUrl = `https://${host}/`;
|
|
48062
48308
|
if (opts.viaTab !== void 0) {
|
|
48063
48309
|
try {
|
|
48064
48310
|
new URL(opts.viaTab);
|
|
48065
48311
|
} catch {
|
|
48066
|
-
throw new Error(`FetchproxyServer
|
|
48312
|
+
throw new Error(`FetchproxyServer.${caller}: viaTab is not a valid URL: ${JSON.stringify(opts.viaTab)}`);
|
|
48067
48313
|
}
|
|
48068
48314
|
assertUrlInDomains("viaTab", opts.viaTab, this.opts.domains);
|
|
48069
48315
|
tabUrl = opts.viaTab;
|
|
48070
48316
|
}
|
|
48071
|
-
|
|
48317
|
+
return {
|
|
48072
48318
|
url: url2,
|
|
48073
48319
|
method,
|
|
48074
48320
|
tabUrl,
|
|
@@ -48083,29 +48329,16 @@ var init_ws_server = __esm({
|
|
|
48083
48329
|
// every version before this option existed.
|
|
48084
48330
|
...opts.credentials === "omit" ? { credentials: "omit" } : {}
|
|
48085
48331
|
};
|
|
48086
|
-
|
|
48087
|
-
|
|
48088
|
-
|
|
48089
|
-
|
|
48090
|
-
|
|
48091
|
-
if (result.kind === "capability_unavailable" && result.cause instanceof FetchproxyCapabilityUnavailableError) {
|
|
48092
|
-
throw result.cause;
|
|
48093
|
-
}
|
|
48094
|
-
throw this._typedErrorFor(result, init.url, "fetch", result.retryAttempted ?? false, isRetrySafeOnTimeout(method, opts.retryOnTimeout));
|
|
48332
|
+
}
|
|
48333
|
+
/** Turn a failed `fetch()` envelope into the throw `request()` has always made. */
|
|
48334
|
+
throwFetchFailure(result, url2, method, retryOnTimeout) {
|
|
48335
|
+
if (result.kind === "session_not_ready" && result.cause instanceof Error) {
|
|
48336
|
+
throw result.cause;
|
|
48095
48337
|
}
|
|
48096
|
-
|
|
48097
|
-
|
|
48098
|
-
body: result.body,
|
|
48099
|
-
url: result.url
|
|
48100
|
-
};
|
|
48101
|
-
if (opts.expectStatus !== void 0) {
|
|
48102
|
-
const expected = opts.expectStatus;
|
|
48103
|
-
const matched = Array.isArray(expected) ? expected.includes(response.status) : response.status === expected;
|
|
48104
|
-
if (!matched) {
|
|
48105
|
-
throw new FetchproxyHttpError(response);
|
|
48106
|
-
}
|
|
48338
|
+
if (result.kind === "capability_unavailable" && result.cause instanceof FetchproxyCapabilityUnavailableError) {
|
|
48339
|
+
throw result.cause;
|
|
48107
48340
|
}
|
|
48108
|
-
|
|
48341
|
+
throw this._typedErrorFor(result, url2, "fetch", result.retryAttempted ?? false, isRetrySafeOnTimeout(method, retryOnTimeout));
|
|
48109
48342
|
}
|
|
48110
48343
|
/** Issue a GET against `path` (resolved via `request()` rules). */
|
|
48111
48344
|
get(path2, opts = {}) {
|
|
@@ -48906,6 +49139,10 @@ var init_ws_server = __esm({
|
|
|
48906
49139
|
status: inner.status,
|
|
48907
49140
|
url: inner.url,
|
|
48908
49141
|
body: inner.body,
|
|
49142
|
+
// #460: carried only when present, so a text answer's envelope
|
|
49143
|
+
// has exactly the keys it always had.
|
|
49144
|
+
...inner.bodyEncoding !== void 0 ? { bodyEncoding: inner.bodyEncoding } : {},
|
|
49145
|
+
...inner.headers !== void 0 ? { headers: { ...inner.headers } } : {},
|
|
48909
49146
|
retryAttempted: false
|
|
48910
49147
|
});
|
|
48911
49148
|
} else {
|
|
@@ -48922,7 +49159,8 @@ var init_ws_server = __esm({
|
|
|
48922
49159
|
ok: false,
|
|
48923
49160
|
error: inner.error,
|
|
48924
49161
|
kind: classifyFetchError(inner.error, inner.code),
|
|
48925
|
-
retryAttempted: false
|
|
49162
|
+
retryAttempted: false,
|
|
49163
|
+
...inner.code !== void 0 ? { code: inner.code } : {}
|
|
48926
49164
|
});
|
|
48927
49165
|
}
|
|
48928
49166
|
return;
|
|
@@ -49226,6 +49464,7 @@ var init_ws_server = __esm({
|
|
|
49226
49464
|
pairCode,
|
|
49227
49465
|
extensionConnected: false,
|
|
49228
49466
|
unavailableCapabilities: [],
|
|
49467
|
+
features: [],
|
|
49229
49468
|
platform: null
|
|
49230
49469
|
};
|
|
49231
49470
|
}
|
|
@@ -49237,6 +49476,7 @@ var init_ws_server = __esm({
|
|
|
49237
49476
|
pairCode,
|
|
49238
49477
|
extensionConnected,
|
|
49239
49478
|
unavailableCapabilities: info ? [...info.unavailableCapabilities] : [],
|
|
49479
|
+
features: info ? [...info.features] : [],
|
|
49240
49480
|
platform: info?.platform ?? null
|
|
49241
49481
|
};
|
|
49242
49482
|
}
|
|
@@ -49250,9 +49490,13 @@ var init_ws_server = __esm({
|
|
|
49250
49490
|
*/
|
|
49251
49491
|
refuseIfUnavailable(inner, info) {
|
|
49252
49492
|
const cap = unavailableCapabilityFor(inner, info);
|
|
49253
|
-
if (cap
|
|
49254
|
-
|
|
49255
|
-
|
|
49493
|
+
if (cap !== null && info !== null) {
|
|
49494
|
+
throw new FetchproxyCapabilityUnavailableError(capabilityUnavailableMessage(cap, info.platform), { capability: cap, platform: info.platform });
|
|
49495
|
+
}
|
|
49496
|
+
const feature = missingFeatureFor(inner, info);
|
|
49497
|
+
if (feature !== null) {
|
|
49498
|
+
throw new FetchproxyExtensionUpdateRequiredError(`the paired ContextMint Bridge extension does not support "${feature}"`, { feature });
|
|
49499
|
+
}
|
|
49256
49500
|
}
|
|
49257
49501
|
/**
|
|
49258
49502
|
* 0.5.2+: throw `FetchproxyProtocolError` with the actionable pair-code
|
|
@@ -49353,6 +49597,7 @@ var init_dist4 = __esm({
|
|
|
49353
49597
|
init_deadline();
|
|
49354
49598
|
init_parse_html();
|
|
49355
49599
|
init_batch();
|
|
49600
|
+
init_dist3();
|
|
49356
49601
|
init_extension_trust();
|
|
49357
49602
|
init_extension_pins();
|
|
49358
49603
|
init_identity();
|
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.10.
|
|
3
|
+
"version": "0.10.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>",
|
|
@@ -47,20 +47,20 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@azure/msal-node": "^7.2.1",
|
|
49
49
|
"@chrischall/mcp-utils": "^3.7.2",
|
|
50
|
-
"@fetchproxy/server": "^3.
|
|
51
|
-
"@modelcontextprotocol/server": "^2.
|
|
52
|
-
"dotenv": "^18.0.
|
|
50
|
+
"@fetchproxy/server": "^3.8.0",
|
|
51
|
+
"@modelcontextprotocol/server": "^2.4.0",
|
|
52
|
+
"dotenv": "^18.0.10",
|
|
53
53
|
"ws": "^8.22.2",
|
|
54
|
-
"zod": "^4.6.
|
|
54
|
+
"zod": "^4.6.7"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@modelcontextprotocol/client": "^2.
|
|
58
|
-
"@types/node": "^26.
|
|
57
|
+
"@modelcontextprotocol/client": "^2.4.0",
|
|
58
|
+
"@types/node": "^26.6.6",
|
|
59
59
|
"@types/ws": "^8.18.2",
|
|
60
|
-
"@vitest/coverage-v8": "^5.
|
|
61
|
-
"esbuild": "^0.28.
|
|
60
|
+
"@vitest/coverage-v8": "^5.1.0",
|
|
61
|
+
"esbuild": "^0.28.2",
|
|
62
62
|
"typescript": "^7.0.2",
|
|
63
|
-
"vitest": "^5.
|
|
63
|
+
"vitest": "^5.1.0"
|
|
64
64
|
},
|
|
65
65
|
"allowScripts": {
|
|
66
66
|
"esbuild": false,
|
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.10.
|
|
9
|
+
"version": "0.10.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@chrischall/office-outlook-mcp",
|
|
14
|
-
"version": "0.10.
|
|
14
|
+
"version": "0.10.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|