@chrischall/office-outlook-mcp 0.3.3 → 0.3.4

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.
@@ -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.3.3"
10
+ "version": "0.3.4"
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 — read mail, folders, calendar, contacts and tasks, and send mail with confirmation",
18
- "version": "0.3.3",
18
+ "version": "0.3.4",
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.3.3",
4
+ "version": "0.3.4",
5
5
  "description": "Outlook / Microsoft 365 for Claude — read mail, folders, calendar, contacts and tasks, and send mail with confirmation, using your signed-in browser session",
6
6
  "author": {
7
7
  "name": "Chris Hall",
package/dist/bundle.js CHANGED
@@ -17821,8 +17821,8 @@ function currencyCode2(_params) {
17821
17821
  return _stringFormat(ZodCustomStringFormat, "currency_code", currencyCode, _params);
17822
17822
  }
17823
17823
  function hash(alg, params) {
17824
- const enc6 = params?.enc ?? "hex";
17825
- const format = `${alg}_${enc6}`;
17824
+ const enc7 = params?.enc ?? "hex";
17825
+ const format = `${alg}_${enc7}`;
17826
17826
  const regex = regexes_exports[format];
17827
17827
  if (!regex)
17828
17828
  throw new Error(`Unrecognized hash format: ${format}`);
@@ -21496,7 +21496,7 @@ var init_internal = __esm({
21496
21496
  }
21497
21497
  });
21498
21498
 
21499
- // node_modules/@modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs
21499
+ // node_modules/@modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs
21500
21500
  function stampErrorBrands(instance, ctor) {
21501
21501
  const brands = /* @__PURE__ */ new Set();
21502
21502
  let current = ctor;
@@ -23476,7 +23476,8 @@ function build() {
23476
23476
  ListResourceTemplatesResultResponseSchema: wireResultResponse(ListResourceTemplatesResultSchema$1),
23477
23477
  ReadResourceResultResponseSchema: wireResultResponse(union([ReadResourceResultSchema$1, InputRequiredResultSchema])),
23478
23478
  CompleteResultResponseSchema: wireResultResponse(CompleteResultSchema$1),
23479
- DiscoverResultResponseSchema: wireResultResponse(DiscoverResultSchema$1)
23479
+ DiscoverResultResponseSchema: wireResultResponse(DiscoverResultSchema$1),
23480
+ SubscriptionsListenResultResponseSchema: wireResultResponse(SubscriptionsListenResultSchema$1)
23480
23481
  };
23481
23482
  }
23482
23483
  function buildSchemas2026() {
@@ -23695,6 +23696,9 @@ function isSpecRequestMethod(method) {
23695
23696
  function isSpecNotificationMethod(method) {
23696
23697
  return ALL_CODECS.some((codec2) => codec2.hasNotificationMethod(method));
23697
23698
  }
23699
+ function isExtensionReusedRequestMethod(method) {
23700
+ return method === "tasks/get" || method === "tasks/cancel";
23701
+ }
23698
23702
  function isPlainObject$3(value) {
23699
23703
  return value !== null && typeof value === "object" && !Array.isArray(value);
23700
23704
  }
@@ -24269,8 +24273,8 @@ function normalizeRawShapeSchema(schema) {
24269
24273
  return schema;
24270
24274
  }
24271
24275
  var BRANDS, OAuthError, SdkErrorCode, SdkError, SdkHttpError, FIRST_MODERN_PROTOCOL_VERSION, SUPPORTED_MODERN_PROTOCOL_VERSIONS, TOOL_RESULT_FOREIGN_FAMILY_KEYS, memo$1, REF_REWRITE_DATA_POSITION_KEYS, REF_REWRITE_NAME_MAP_KEYS, requestMethodKeys$1, notificationMethodKeys$1, resultMethodKeys, maps$1, rev2025RequestMethods, rev2025NotificationMethods, NOT_IN_ERA$1, rev2025Codec, memo2, CACHEABLE_RESULT_METHODS, RESULT_CACHE_HINT_FALLBACK, ProtocolErrorCode, ProtocolError, ResourceNotFoundError, UrlElicitationRequiredError, UnsupportedProtocolVersionError, MissingRequiredClientCapabilityError, DEFAULT_CACHE_TTL_MS, DEFAULT_CACHE_SCOPE, EXTENDED_RESULT_TYPE_METHODS, INPUT_REQUEST_METHODS_2026, maps, requestMethodKeys, notificationMethodKeys, rev2026RequestMethods, rev2026NotificationMethods, NOT_IN_ERA, REQUIRED_ENVELOPE_KEYS, rev2026Codec, wireResultSchemasMemo, MODERN_WIRE_REVISION, ALL_CODECS, schemas_exports3, isJSONRPCRequest, isJSONRPCNotification, isJSONRPCResultResponse, isJSONRPCErrorResponse, isInputRequiredResult, X_MCP_HEADER_KEY, RFC9110_TOKEN, PERMITTED_X_MCP_HEADER_TYPES, NON_REACHABLE_SUBSCHEMA_KEYWORDS, OBJECT_VALUED_SUBSCHEMA_KEYWORDS, HEADER_MISMATCH_ERROR_CODE, INBOUND_VALIDATION_LADDER, LADDER_ERROR_HTTP_STATUS, warnedZodFallback, JSON_SCHEMA_CONVERSION_TARGET, DATETIME_FRACTION_DIGITS, ANNOTATION_ONLY_JSON_SCHEMA_KEYWORDS, ROOT_KEYS, PROPERTY_KEYS_BY_TYPE, SUPPORTED_STRING_FORMATS, inputRequired, REQUEST_STATE_ONLY_LEG_PACING_MS, SPEC_SCHEMA_KEYS, authSchemas, _specTypeSchemas, _isSpecType, specTypeSchemas, isSpecType, DEFAULT_REQUEST_TIMEOUT_MSEC, RESERVED_ENVELOPE_META_KEYS, RETRY_PARAMS_KEYS, NO_REQUEST_STATE, writeNegotiatedProtocolVersion, Protocol, require_content_type, import_content_type, STDIO_DEFAULT_MAX_BUFFER_SIZE, ReadBuffer, TOOL_NAME_REGEX;
24272
- var init_src_BHSMhZ_W = __esm({
24273
- "node_modules/@modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs"() {
24276
+ var init_src_Cqbh3MYc = __esm({
24277
+ "node_modules/@modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs"() {
24274
24278
  init_chunk_Br0eD_fh();
24275
24279
  init_dialects_DoSzNhcb();
24276
24280
  init_internal();
@@ -25370,6 +25374,8 @@ var init_src_BHSMhZ_W = __esm({
25370
25374
  _transport;
25371
25375
  _requestMessageId = 0;
25372
25376
  _requestHandlers = /* @__PURE__ */ new Map();
25377
+ /** Methods registered with an explicit schema; the era gate in `_onrequest` reads it for the Tasks extension names. */
25378
+ _customSchemaRequestMethods = /* @__PURE__ */ new Set();
25373
25379
  _requestHandlerAbortControllers = /* @__PURE__ */ new Map();
25374
25380
  _notificationHandlers = /* @__PURE__ */ new Map();
25375
25381
  _responseHandlers = /* @__PURE__ */ new Map();
@@ -25653,7 +25659,7 @@ var init_src_BHSMhZ_W = __esm({
25653
25659
  return;
25654
25660
  }
25655
25661
  }
25656
- if (isSpecRequestMethod(request.method) && !codec2.hasRequestMethod(request.method)) {
25662
+ if (isSpecRequestMethod(request.method) && !codec2.hasRequestMethod(request.method) && !(isExtensionReusedRequestMethod(request.method) && this._customSchemaRequestMethods.has(request.method))) {
25657
25663
  sendErrorResponse(ProtocolErrorCode.MethodNotFound, "Method not found");
25658
25664
  return;
25659
25665
  }
@@ -25786,8 +25792,11 @@ var init_src_BHSMhZ_W = __esm({
25786
25792
  }
25787
25793
  request(request, schemaOrOptions, maybeOptions) {
25788
25794
  const codec2 = this._resolveOutboundCodec(request.method);
25795
+ if (isStandardSchema(schemaOrOptions)) {
25796
+ if (!isExtensionReusedRequestMethod(request.method)) this._assertOutboundRequestInEra(codec2, request.method);
25797
+ return this._requestWithSchemaViaCodec(codec2, request, schemaOrOptions, maybeOptions);
25798
+ }
25789
25799
  this._assertOutboundRequestInEra(codec2, request.method);
25790
- if (isStandardSchema(schemaOrOptions)) return this._requestWithSchemaViaCodec(codec2, request, schemaOrOptions, maybeOptions);
25791
25800
  const validate2 = codecResultValidator(codec2, request.method);
25792
25801
  if (validate2 === void 0) throw new TypeError(`'${request.method}' is not a spec method; pass a result schema as the second argument to request().`);
25793
25802
  return this._requestWithSchemaViaCodec(codec2, request, validate2, schemaOrOptions);
@@ -26031,6 +26040,8 @@ var init_src_BHSMhZ_W = __esm({
26031
26040
  return maybeHandler(parsed.data, ctx);
26032
26041
  };
26033
26042
  else throw new TypeError("setRequestHandler: handler is required");
26043
+ if (typeof schemasOrHandler === "function") this._customSchemaRequestMethods.delete(method);
26044
+ else this._customSchemaRequestMethods.add(method);
26034
26045
  this._requestHandlers.set(method, this._wrapHandler(method, stored));
26035
26046
  }
26036
26047
  /**
@@ -26060,6 +26071,7 @@ var init_src_BHSMhZ_W = __esm({
26060
26071
  */
26061
26072
  removeRequestHandler(method) {
26062
26073
  this._requestHandlers.delete(method);
26074
+ this._customSchemaRequestMethods.delete(method);
26063
26075
  }
26064
26076
  /**
26065
26077
  * Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
@@ -33202,7 +33214,7 @@ var init_shimsNode = __esm({
33202
33214
  }
33203
33215
  });
33204
33216
 
33205
- // node_modules/@modelcontextprotocol/server/dist/mcp-DYuW2ZSs.mjs
33217
+ // node_modules/@modelcontextprotocol/server/dist/mcp-DIH4cS6P.mjs
33206
33218
  function isCompletable(schema) {
33207
33219
  return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
33208
33220
  }
@@ -33312,6 +33324,30 @@ function serverIdentityOf(server) {
33312
33324
  function discoverAdvertisedCapabilities(capabilities) {
33313
33325
  return { ...capabilities };
33314
33326
  }
33327
+ function toolInputElementCount(value, max) {
33328
+ let count = 0;
33329
+ const stack = [value];
33330
+ while (stack.length > 0) {
33331
+ const node2 = stack.pop();
33332
+ if (node2 === null || typeof node2 !== "object") continue;
33333
+ if (Array.isArray(node2)) for (const child of node2) {
33334
+ if (++count > max) return count;
33335
+ if (child !== null && typeof child === "object") stack.push(child);
33336
+ }
33337
+ else for (const key in node2) {
33338
+ if (!Object.prototype.hasOwnProperty.call(node2, key)) continue;
33339
+ if (++count > max) return count;
33340
+ const child = node2[key];
33341
+ if (child !== null && typeof child === "object") stack.push(child);
33342
+ }
33343
+ }
33344
+ return count;
33345
+ }
33346
+ function resolveMaxToolInputElements(value) {
33347
+ if (value === void 0 || value === Infinity) return void 0;
33348
+ if (typeof value !== "number" || Number.isNaN(value) || value < 1) throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
33349
+ return value;
33350
+ }
33315
33351
  function createToolExecutor(inputSchema, handler) {
33316
33352
  if (inputSchema) {
33317
33353
  const callback$1 = handler;
@@ -33320,6 +33356,12 @@ function createToolExecutor(inputSchema, handler) {
33320
33356
  const callback = handler;
33321
33357
  return async (_args, ctx) => callback(ctx);
33322
33358
  }
33359
+ function convertListedInputSchema(name, inputSchema) {
33360
+ const json2 = standardSchemaToJsonSchema(inputSchema, "input");
33361
+ const scan = scanXMcpHeaderDeclarations(json2);
33362
+ if (!scan.valid) console.warn(`[mcp-sdk] tool '${name}' carries an invalid x-mcp-header declaration and will be excluded by conforming Streamable HTTP clients: ${scan.reason}`);
33363
+ return json2;
33364
+ }
33323
33365
  function convertOutputSchemaJson(outputSchema) {
33324
33366
  if (outputSchema === void 0) return void 0;
33325
33367
  try {
@@ -33332,7 +33374,7 @@ function createPromptHandler(name, argsSchema, callback) {
33332
33374
  if (argsSchema) {
33333
33375
  const typedCallback = callback;
33334
33376
  return async (args, ctx) => {
33335
- const parseResult = await validateStandardSchema(argsSchema, args);
33377
+ const parseResult = await validateStandardSchema(argsSchema, args ?? {});
33336
33378
  if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: ${parseResult.error}`);
33337
33379
  return typedCallback(parseResult.data, ctx);
33338
33380
  };
@@ -33362,9 +33404,9 @@ function unwrapOptionalSchema(schema) {
33362
33404
  return schema.def?.innerType ?? schema;
33363
33405
  }
33364
33406
  var COMPLETABLE_SYMBOL, MAX_TIMER_DELAY_MS, DEFAULT_MAX_SUBSCRIPTIONS, CHANGE_NOTIFICATION_METHODS, StdioListenRouter, DEFAULT_LEGACY_SHIM_MAX_ROUNDS, DEFAULT_LEGACY_SHIM_ROUND_TIMEOUT_MS, LegacyInputRequiredShim, INPUT_REQUIRED_CAPABLE_METHODS, writeClientIdentity, installDiscoverHandler, readServerIdentity, Server, McpServer, EMPTY_OBJECT_JSON_SCHEMA, EMPTY_COMPLETION_RESULT;
33365
- var init_mcp_DYuW2ZSs = __esm({
33366
- "node_modules/@modelcontextprotocol/server/dist/mcp-DYuW2ZSs.mjs"() {
33367
- init_src_BHSMhZ_W();
33407
+ var init_mcp_DIH4cS6P = __esm({
33408
+ "node_modules/@modelcontextprotocol/server/dist/mcp-DIH4cS6P.mjs"() {
33409
+ init_src_Cqbh3MYc();
33368
33410
  init_shimsNode();
33369
33411
  COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
33370
33412
  MAX_TIMER_DELAY_MS = 2 ** 31 - 1;
@@ -33387,7 +33429,7 @@ var init_mcp_DYuW2ZSs = __esm({
33387
33429
  _serverCapabilities;
33388
33430
  /**
33389
33431
  * The serving instance's identity, stamped onto the graceful-close
33390
- * results' `_meta` (the spec's `SubscriptionsListenResultMeta` extends
33432
+ * results' `_meta` (the spec's `SubscriptionsListenResultMetaObject` extends
33391
33433
  * `ResultMetaObject`). Handed over together with the capabilities.
33392
33434
  */
33393
33435
  _serverInfo;
@@ -33653,6 +33695,11 @@ var init_mcp_DYuW2ZSs = __esm({
33653
33695
  if (modernProtocolVersions(this._supportedProtocolVersions).length > 0) this.setRequestHandler("server/discover", () => this._ondiscover());
33654
33696
  if (this._capabilities.logging) this._registerLoggingHandler();
33655
33697
  }
33698
+ /** Attaches to the given transport; rejects while this instance is connected to another one. */
33699
+ async connect(transport) {
33700
+ if (this.transport !== void 0) throw new SdkError(SdkErrorCode.AlreadyConnected, "Use a separate Server instance per connection: this instance is already connected to a transport. To connect it to a new transport, call close() first.");
33701
+ await super.connect(transport);
33702
+ }
33656
33703
  /**
33657
33704
  * Registers the built-in `logging/setLevel` request handler.
33658
33705
  *
@@ -34208,16 +34255,12 @@ var init_mcp_DYuW2ZSs = __esm({
34208
34255
  * The underlying {@linkcode Server} instance, useful for advanced operations like sending notifications.
34209
34256
  */
34210
34257
  server;
34258
+ _maxToolInputElements;
34211
34259
  _registeredResources = {};
34212
34260
  _registeredResourceTemplates = {};
34213
34261
  _registeredTools = {};
34214
34262
  _registeredPrompts = {};
34215
- /**
34216
- * Per-tool JSON-converted `inputSchema`, memoized so the SEP-2243
34217
- * registration-time scan and the pre-dispatch validation step share one
34218
- * conversion instead of paying it twice per request under the
34219
- * per-request-factory `createMcpHandler` model.
34220
- */
34263
+ /** Per-tool JSON-converted `inputSchema`, filled on first use by `toolInputSchemaJson()`. */
34221
34264
  _toolInputSchemaJson = {};
34222
34265
  /**
34223
34266
  * The JSON-serialized `inputSchema` of a registered tool, or `undefined`
@@ -34242,6 +34285,7 @@ var init_mcp_DYuW2ZSs = __esm({
34242
34285
  }
34243
34286
  constructor(serverInfo, options) {
34244
34287
  this.server = new Server(serverInfo, options);
34288
+ this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
34245
34289
  if (options?.capabilities?.tools) this.setToolRequestHandlers();
34246
34290
  if (options?.capabilities?.resources) this.setResourceRequestHandlers();
34247
34291
  if (options?.capabilities?.prompts) this.setPromptRequestHandlers();
@@ -34314,7 +34358,7 @@ var init_mcp_DYuW2ZSs = __esm({
34314
34358
  name,
34315
34359
  title: tool.title,
34316
34360
  description: tool.description,
34317
- inputSchema: tool.inputSchema ? standardSchemaToJsonSchema(tool.inputSchema, "input") : EMPTY_OBJECT_JSON_SCHEMA,
34361
+ inputSchema: tool.inputSchema ? convertListedInputSchema(name, tool.inputSchema) : EMPTY_OBJECT_JSON_SCHEMA,
34318
34362
  annotations: tool.annotations,
34319
34363
  icons: tool.icons,
34320
34364
  execution: tool.execution,
@@ -34359,6 +34403,7 @@ var init_mcp_DYuW2ZSs = __esm({
34359
34403
  * Validates tool input arguments against the tool's input schema.
34360
34404
  */
34361
34405
  async validateToolInput(tool, args, toolName) {
34406
+ if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
34362
34407
  if (!tool.inputSchema) return;
34363
34408
  const parseResult = await validateStandardSchema(tool.inputSchema, args ?? {});
34364
34409
  if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${parseResult.error}`);
@@ -34633,20 +34678,19 @@ var init_mcp_DYuW2ZSs = __esm({
34633
34678
  }
34634
34679
  _createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, icons, execution, scopeChallenge, _meta, handler) {
34635
34680
  validateAndWarnToolName(name);
34636
- if (inputSchema !== void 0) try {
34637
- const json2 = standardSchemaToJsonSchema(inputSchema, "input");
34638
- this._toolInputSchemaJson[name] = json2;
34639
- const scan = scanXMcpHeaderDeclarations(json2);
34640
- if (!scan.valid) console.warn(`[mcp-sdk] tool '${name}' carries an invalid x-mcp-header declaration and will be excluded by conforming Streamable HTTP clients: ${scan.reason}`);
34641
- } catch {
34642
- }
34643
34681
  let currentHandler = handler;
34682
+ let outputSchemaJson;
34644
34683
  const registeredTool = {
34645
34684
  title,
34646
34685
  description,
34647
34686
  inputSchema,
34648
34687
  outputSchema,
34649
- outputSchemaJson: convertOutputSchemaJson(outputSchema),
34688
+ get outputSchemaJson() {
34689
+ return outputSchemaJson ??= convertOutputSchemaJson(registeredTool.outputSchema);
34690
+ },
34691
+ set outputSchemaJson(value) {
34692
+ outputSchemaJson = value;
34693
+ },
34650
34694
  annotations,
34651
34695
  icons,
34652
34696
  execution,
@@ -35090,8 +35134,8 @@ function toError(value) {
35090
35134
  var swallowsErrorsAfterClose, StdioServerTransport, DISCARD_ANSWER_TIMEOUT_MS, StdioConnectionChannel;
35091
35135
  var init_stdio = __esm({
35092
35136
  "node_modules/@modelcontextprotocol/server/dist/stdio.mjs"() {
35093
- init_mcp_DYuW2ZSs();
35094
- init_src_BHSMhZ_W();
35137
+ init_mcp_DIH4cS6P();
35138
+ init_src_Cqbh3MYc();
35095
35139
  init_shimsNode();
35096
35140
  swallowsErrorsAfterClose = /* @__PURE__ */ Symbol("swallowsErrorsAfterClose");
35097
35141
  StdioServerTransport = class {
@@ -35282,8 +35326,8 @@ var init_stdio = __esm({
35282
35326
  var DEFAULT_MAX_REQUEST_BODY_SIZE;
35283
35327
  var init_dist = __esm({
35284
35328
  "node_modules/@modelcontextprotocol/server/dist/index.mjs"() {
35285
- init_mcp_DYuW2ZSs();
35286
- init_src_BHSMhZ_W();
35329
+ init_mcp_DIH4cS6P();
35330
+ init_src_Cqbh3MYc();
35287
35331
  init_shimsNode();
35288
35332
  DEFAULT_MAX_REQUEST_BODY_SIZE = 4 * 1024 * 1024;
35289
35333
  }
@@ -36276,7 +36320,10 @@ function surfaceToolHints(server) {
36276
36320
  ));
36277
36321
  }
36278
36322
  async function createMcpServer(opts) {
36279
- const server = new McpServer({ name: opts.name, version: opts.version }, { supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS] });
36323
+ const server = new McpServer({ name: opts.name, version: opts.version }, {
36324
+ supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS],
36325
+ ...opts.maxToolInputElements !== void 0 ? { maxToolInputElements: opts.maxToolInputElements } : {}
36326
+ });
36280
36327
  if (opts.surfaceHints !== false)
36281
36328
  surfaceToolHints(server);
36282
36329
  if (opts.banner !== void 0) {
@@ -36458,6 +36505,21 @@ var init_fs = __esm({
36458
36505
  }
36459
36506
  });
36460
36507
 
36508
+ // node_modules/@chrischall/mcp-utils/dist/internal/headers.js
36509
+ function responseHeader(res, name) {
36510
+ return getHeader(res?.headers, name);
36511
+ }
36512
+ function getHeader(headers, name) {
36513
+ if (!headers || typeof headers.get !== "function")
36514
+ return null;
36515
+ const value = headers.get.call(headers, name);
36516
+ return typeof value === "string" ? value : null;
36517
+ }
36518
+ var init_headers = __esm({
36519
+ "node_modules/@chrischall/mcp-utils/dist/internal/headers.js"() {
36520
+ }
36521
+ });
36522
+
36461
36523
  // node_modules/@chrischall/mcp-utils/dist/internal/ascii.js
36462
36524
  var init_ascii = __esm({
36463
36525
  "node_modules/@chrischall/mcp-utils/dist/internal/ascii.js"() {
@@ -36708,7 +36770,7 @@ function createApiClient(opts) {
36708
36770
  if (retryStatuses.includes(res.status) && attempt < retry.count) {
36709
36771
  discard(current);
36710
36772
  attempt += 1;
36711
- const delay = retry.honorRetryAfter ? parseRetryAfterMs(res.headers.get("retry-after"), {
36773
+ const delay = retry.honorRetryAfter ? parseRetryAfterMs(responseHeader(res, "retry-after"), {
36712
36774
  defaultMs: retry.delayMs,
36713
36775
  capMs: retry.maxRetryAfterMs ?? 3e4
36714
36776
  }) : retry.delayMs;
@@ -36721,7 +36783,7 @@ function createApiClient(opts) {
36721
36783
  async function unauthorizedOrEdge(attempt, method, path) {
36722
36784
  const res = attempt.res;
36723
36785
  let text = "";
36724
- if (/json/i.test(res.headers.get("content-type") ?? "")) {
36786
+ if (/json/i.test(responseHeader(res, "content-type") ?? "")) {
36725
36787
  discard(attempt);
36726
36788
  } else {
36727
36789
  text = await readBody(attempt, (r) => r.text()).catch(() => "");
@@ -36733,14 +36795,14 @@ function createApiClient(opts) {
36733
36795
  }
36734
36796
  async function rateLimitedError(attempt, method, path) {
36735
36797
  const res = attempt.res;
36736
- const retryAfter = res.headers.get("retry-after");
36798
+ const retryAfter = responseHeader(res, "retry-after");
36737
36799
  const retryAfterMs = retryAfterToMs(retryAfter);
36738
36800
  if (!opts.onRateLimited) {
36739
36801
  discard(attempt);
36740
36802
  return new RateLimitedError(service, retryAfterMs);
36741
36803
  }
36742
36804
  let text = "";
36743
- if (/json/i.test(res.headers.get("content-type") ?? "")) {
36805
+ if (/json/i.test(responseHeader(res, "content-type") ?? "")) {
36744
36806
  discard(attempt);
36745
36807
  } else {
36746
36808
  text = await readBody(attempt, (r) => r.text()).catch(() => "");
@@ -36800,7 +36862,7 @@ function createApiClient(opts) {
36800
36862
  const bytes = new Uint8Array(await readBody(attempt, (r) => r.arrayBuffer()));
36801
36863
  return {
36802
36864
  status: res.status,
36803
- contentType: res.headers.get("content-type"),
36865
+ contentType: responseHeader(res, "content-type"),
36804
36866
  headers: res.headers,
36805
36867
  bytes
36806
36868
  };
@@ -36860,6 +36922,7 @@ function decodeJwtExp(token) {
36860
36922
  var DEFAULT_RETRY, defaultSleep, UnauthorizedError, RateLimitedError, RequestTimeoutError, ApiError, EdgeBlockedError, EDGE_BLOCK_SCAN_MAX, EDGE_BLOCK_MARKERS;
36861
36923
  var init_http = __esm({
36862
36924
  "node_modules/@chrischall/mcp-utils/dist/http/index.js"() {
36925
+ init_headers();
36863
36926
  init_cancel();
36864
36927
  init_errors3();
36865
36928
  init_scrape();
@@ -37023,6 +37086,7 @@ var init_es256 = __esm({
37023
37086
  // node_modules/@chrischall/mcp-utils/dist/auth/index.js
37024
37087
  var init_auth = __esm({
37025
37088
  "node_modules/@chrischall/mcp-utils/dist/auth/index.js"() {
37089
+ init_headers();
37026
37090
  init_config();
37027
37091
  init_errors3();
37028
37092
  init_http();
@@ -37056,7 +37120,7 @@ var init_version = __esm({
37056
37120
  "src/version.ts"() {
37057
37121
  "use strict";
37058
37122
  PACKAGE_NAME = "office-outlook-mcp";
37059
- VERSION = "0.3.3";
37123
+ VERSION = "0.3.4";
37060
37124
  }
37061
37125
  });
37062
37126
 
@@ -37308,7 +37372,7 @@ async function transcriptHash(mcpNonce, extNonce, mcpSessionPub, extSessionPub)
37308
37372
  function frameAad(mcpId, seq, direction) {
37309
37373
  return enc.encode(`fetchproxy/4/frame\0${mcpId}\0${seq}\0${direction}`);
37310
37374
  }
37311
- var PROTOCOL_VERSION, HKDF_SESSION_INFO, enc, ANSWERS_NO_EXT_SESSION, KNOWN_CAPABILITIES;
37375
+ var PROTOCOL_VERSION, HKDF_SESSION_INFO, enc, ANSWERS_NO_EXT_SESSION, KNOWN_CAPABILITIES, ACCOUNT_KEY_FRAME, ACCOUNT_ATTEST_FRAME;
37312
37376
  var init_frames = __esm({
37313
37377
  "node_modules/@fetchproxy/protocol/dist/frames.js"() {
37314
37378
  init_crypto();
@@ -37332,6 +37396,67 @@ var init_frames = __esm({
37332
37396
  "graphql",
37333
37397
  "write_cookies"
37334
37398
  ]);
37399
+ ACCOUNT_KEY_FRAME = "account-key";
37400
+ ACCOUNT_ATTEST_FRAME = "account-attest";
37401
+ }
37402
+ });
37403
+
37404
+ // node_modules/@fetchproxy/protocol/dist/mcp-id.js
37405
+ function generateMcpId(serverName, version2) {
37406
+ if (serverName.includes(":")) {
37407
+ throw new Error(`serverName cannot contain ':': ${serverName}`);
37408
+ }
37409
+ if (version2.includes(":")) {
37410
+ throw new Error(`version cannot contain ':': ${version2}`);
37411
+ }
37412
+ const rand = randomHex(8);
37413
+ return `${serverName}:${version2}:${rand}`;
37414
+ }
37415
+ function isValidMcpId(id) {
37416
+ return typeof id === "string" && ID_RE.test(id);
37417
+ }
37418
+ function randomHex(bytes) {
37419
+ const arr = new Uint8Array(bytes);
37420
+ globalThis.crypto.getRandomValues(arr);
37421
+ return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
37422
+ }
37423
+ var ID_RE;
37424
+ var init_mcp_id = __esm({
37425
+ "node_modules/@fetchproxy/protocol/dist/mcp-id.js"() {
37426
+ ID_RE = /^([^:]+):([^:]+):([0-9a-f]{16})$/;
37427
+ }
37428
+ });
37429
+
37430
+ // node_modules/@fetchproxy/protocol/dist/account-attest.js
37431
+ var ACCOUNT_ATTEST_CONSENTS, NO_SCOPE_DIGEST, ACCOUNT_ID_RE, HEX64_RE, ACCOUNT_KID_RE, enc2;
37432
+ var init_account_attest = __esm({
37433
+ "node_modules/@fetchproxy/protocol/dist/account-attest.js"() {
37434
+ init_crypto();
37435
+ init_encoding();
37436
+ init_mcp_id();
37437
+ ACCOUNT_ATTEST_CONSENTS = Object.freeze([
37438
+ "silent",
37439
+ "confirm",
37440
+ "confirm-each"
37441
+ ]);
37442
+ NO_SCOPE_DIGEST = "0".repeat(64);
37443
+ ACCOUNT_ID_RE = /^[A-Za-z0-9_.\-]{1,128}$/;
37444
+ HEX64_RE = /^[0-9a-f]{64}$/;
37445
+ ACCOUNT_KID_RE = /^[0-9a-f]{16}$/;
37446
+ enc2 = new TextEncoder();
37447
+ }
37448
+ });
37449
+
37450
+ // node_modules/@fetchproxy/protocol/dist/awaiting-approval.js
37451
+ function parseAwaitingApprovalReason(reason) {
37452
+ if (!reason.startsWith(AWAITING_APPROVAL_REASON_PREFIX))
37453
+ return null;
37454
+ return reason.slice(AWAITING_APPROVAL_REASON_PREFIX.length).trim();
37455
+ }
37456
+ var AWAITING_APPROVAL_REASON_PREFIX;
37457
+ var init_awaiting_approval = __esm({
37458
+ "node_modules/@fetchproxy/protocol/dist/awaiting-approval.js"() {
37459
+ AWAITING_APPROVAL_REASON_PREFIX = "awaiting-approval:";
37335
37460
  }
37336
37461
  });
37337
37462
 
@@ -37364,32 +37489,6 @@ var init_capability_availability = __esm({
37364
37489
  }
37365
37490
  });
37366
37491
 
37367
- // node_modules/@fetchproxy/protocol/dist/mcp-id.js
37368
- function generateMcpId(serverName, version2) {
37369
- if (serverName.includes(":")) {
37370
- throw new Error(`serverName cannot contain ':': ${serverName}`);
37371
- }
37372
- if (version2.includes(":")) {
37373
- throw new Error(`version cannot contain ':': ${version2}`);
37374
- }
37375
- const rand = randomHex(8);
37376
- return `${serverName}:${version2}:${rand}`;
37377
- }
37378
- function isValidMcpId(id) {
37379
- return typeof id === "string" && ID_RE.test(id);
37380
- }
37381
- function randomHex(bytes) {
37382
- const arr = new Uint8Array(bytes);
37383
- globalThis.crypto.getRandomValues(arr);
37384
- return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
37385
- }
37386
- var ID_RE;
37387
- var init_mcp_id = __esm({
37388
- "node_modules/@fetchproxy/protocol/dist/mcp-id.js"() {
37389
- ID_RE = /^([^:]+):([^:]+):([0-9a-f]{16})$/;
37390
- }
37391
- });
37392
-
37393
37492
  // node_modules/@fetchproxy/protocol/dist/json-pointer.js
37394
37493
  function matchesDeclaredKey(requested, declared) {
37395
37494
  for (const decl of declared) {
@@ -37978,6 +38077,10 @@ function validateFrame(raw) {
37978
38077
  return { type: "extension-disconnected" };
37979
38078
  if (t === "peer-gone")
37980
38079
  return validatePeerGone(raw);
38080
+ if (t === ACCOUNT_KEY_FRAME)
38081
+ return validateAccountKey(raw);
38082
+ if (t === ACCOUNT_ATTEST_FRAME)
38083
+ return validateAccountAttest(raw);
37981
38084
  throw new ProtocolError3(`unknown frame type: ${String(t)}`);
37982
38085
  }
37983
38086
  function validateHello(raw) {
@@ -38180,6 +38283,99 @@ function validateHelloRejected(raw) {
38180
38283
  }
38181
38284
  return { type: "hello-rejected", mcpId: raw.mcpId, reason: raw.reason };
38182
38285
  }
38286
+ function assertExactFields(raw, allowed, label) {
38287
+ for (const k of Object.keys(raw)) {
38288
+ if (!allowed.includes(k)) {
38289
+ throw new ProtocolError3(`${label}: unexpected field ${JSON.stringify(k)}`);
38290
+ }
38291
+ }
38292
+ }
38293
+ function assertMatch(x, re, label, what) {
38294
+ assertString(x, label);
38295
+ if (!re.test(x))
38296
+ throw new ProtocolError3(`${label}: must be ${what}`);
38297
+ }
38298
+ function assertPositiveSafeInt(x, label) {
38299
+ if (typeof x !== "number" || !Number.isSafeInteger(x) || x <= 0) {
38300
+ throw new ProtocolError3(`${label}: expected positive safe integer`);
38301
+ }
38302
+ }
38303
+ function assertDisplayString(x, label, min, max) {
38304
+ assertString(x, label);
38305
+ if (x.length < min || x.length > max) {
38306
+ throw new ProtocolError3(`${label}: must be ${min}-${max} characters`);
38307
+ }
38308
+ if (DISPLAY_FORBIDDEN_RE.test(x)) {
38309
+ throw new ProtocolError3(`${label}: control or bidi-override character`);
38310
+ }
38311
+ }
38312
+ function validateAccountKey(raw) {
38313
+ const L = "account-key";
38314
+ assertMatch(raw.accountId, ACCOUNT_ID_RE, `${L}.accountId`, "an account id");
38315
+ assertMatch(raw.slug, ACCOUNT_ID_RE, `${L}.slug`, "a slug");
38316
+ assertDisplayString(raw.displayName, `${L}.displayName`, 0, 128);
38317
+ assertDisplayString(raw.confirmedBy, `${L}.confirmedBy`, 1, 256);
38318
+ assertMatch(raw.tokenId, ACCOUNT_ID_RE, `${L}.tokenId`, "a token id");
38319
+ assertMatch(raw.kid, ACCOUNT_KID_RE, `${L}.kid`, "16 lowercase hex");
38320
+ assertBase64Bytes(raw.publicKey, `${L}.publicKey`, 32);
38321
+ assertPositiveSafeInt(raw.generation, `${L}.generation`);
38322
+ const n = raw.bridgedRegistrations;
38323
+ if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 0) {
38324
+ throw new ProtocolError3(`${L}.bridgedRegistrations: expected non-negative safe integer`);
38325
+ }
38326
+ assertExactFields(raw, ACCOUNT_KEY_FIELDS, L);
38327
+ return {
38328
+ type: ACCOUNT_KEY_FRAME,
38329
+ accountId: raw.accountId,
38330
+ slug: raw.slug,
38331
+ displayName: raw.displayName,
38332
+ confirmedBy: raw.confirmedBy,
38333
+ tokenId: raw.tokenId,
38334
+ kid: raw.kid,
38335
+ publicKey: raw.publicKey,
38336
+ generation: raw.generation,
38337
+ bridgedRegistrations: n
38338
+ };
38339
+ }
38340
+ function validateAccountAttest(raw) {
38341
+ const L = "account-attest";
38342
+ if (!isValidMcpId(raw.mcpId))
38343
+ throw new ProtocolError3(`${L}.mcpId: invalid format`);
38344
+ assertMatch(raw.accountId, ACCOUNT_ID_RE, `${L}.accountId`, "an account id");
38345
+ assertPositiveSafeInt(raw.generation, `${L}.generation`);
38346
+ assertMatch(raw.tokenId, ACCOUNT_ID_RE, `${L}.tokenId`, "a token id");
38347
+ assertMatch(raw.kid, ACCOUNT_KID_RE, `${L}.kid`, "16 lowercase hex");
38348
+ assertMatch(raw.registrationId, ACCOUNT_ID_RE, `${L}.registrationId`, "a registration id");
38349
+ assertMatch(raw.slug, ACCOUNT_ID_RE, `${L}.slug`, "a slug");
38350
+ assertMatch(raw.identityHash, HEX64_RE, `${L}.identityHash`, "64 lowercase hex");
38351
+ assertBase64Bytes(raw.identityEd25519Pub, `${L}.identityEd25519Pub`, 32);
38352
+ assertMatch(raw.scopeDigest, HEX64_RE, `${L}.scopeDigest`, "64 lowercase hex");
38353
+ assertString(raw.consent, `${L}.consent`);
38354
+ const consent = raw.consent;
38355
+ const known = ACCOUNT_ATTEST_CONSENTS.find((c) => c === consent);
38356
+ if (known === void 0) {
38357
+ throw new ProtocolError3(`${L}.consent: must be one of ${ACCOUNT_ATTEST_CONSENTS.join(", ")}`);
38358
+ }
38359
+ assertPositiveSafeInt(raw.notAfter, `${L}.notAfter`);
38360
+ assertBase64Bytes(raw.sig, `${L}.sig`, 64);
38361
+ assertExactFields(raw, ACCOUNT_ATTEST_FIELDS, L);
38362
+ return {
38363
+ type: ACCOUNT_ATTEST_FRAME,
38364
+ mcpId: raw.mcpId,
38365
+ accountId: raw.accountId,
38366
+ generation: raw.generation,
38367
+ tokenId: raw.tokenId,
38368
+ kid: raw.kid,
38369
+ registrationId: raw.registrationId,
38370
+ slug: raw.slug,
38371
+ identityHash: raw.identityHash,
38372
+ identityEd25519Pub: raw.identityEd25519Pub,
38373
+ scopeDigest: raw.scopeDigest,
38374
+ consent: known,
38375
+ notAfter: raw.notAfter,
38376
+ sig: raw.sig
38377
+ };
38378
+ }
38183
38379
  function validateInnerFrame(raw) {
38184
38380
  assertObject(raw, "inner");
38185
38381
  const t = raw.type;
@@ -38641,12 +38837,13 @@ function validateInnerResponse(raw) {
38641
38837
  }
38642
38838
  throw new ProtocolError3(`inner.ok: must be boolean, got ${typeof raw.ok}`);
38643
38839
  }
38644
- var ProtocolError3, FORBIDDEN_KEYS, BASE64_RE, 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, KNOWN_RESPONSE_OPS;
38840
+ var ProtocolError3, FORBIDDEN_KEYS, BASE64_RE, 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, KNOWN_RESPONSE_OPS;
38645
38841
  var init_validate = __esm({
38646
38842
  "node_modules/@fetchproxy/protocol/dist/validate.js"() {
38647
38843
  init_frames();
38648
38844
  init_capability_availability();
38649
38845
  init_mcp_id();
38846
+ init_account_attest();
38650
38847
  init_json_pointer();
38651
38848
  init_public_suffix();
38652
38849
  ProtocolError3 = class extends Error {
@@ -38666,6 +38863,35 @@ var init_validate = __esm({
38666
38863
  DOM_ATTRIBUTE_RE = /^[A-Za-z_:][A-Za-z0-9_:.\-]{0,127}$/;
38667
38864
  GRAPHQL_OP_NAME_RE = /^[_A-Za-z][_0-9A-Za-z]{0,127}$/;
38668
38865
  PAIR_CODE_RE = /^\d{4}-\d{4}$/;
38866
+ DISPLAY_FORBIDDEN_RE = /[\u0000-\u001f\u007f-\u009f\u200e\u200f\u202a-\u202e\u2066-\u2069]/;
38867
+ ACCOUNT_KEY_FIELDS = [
38868
+ "type",
38869
+ "accountId",
38870
+ "slug",
38871
+ "displayName",
38872
+ "confirmedBy",
38873
+ "tokenId",
38874
+ "kid",
38875
+ "publicKey",
38876
+ "generation",
38877
+ "bridgedRegistrations"
38878
+ ];
38879
+ ACCOUNT_ATTEST_FIELDS = [
38880
+ "type",
38881
+ "mcpId",
38882
+ "accountId",
38883
+ "generation",
38884
+ "tokenId",
38885
+ "kid",
38886
+ "registrationId",
38887
+ "slug",
38888
+ "identityHash",
38889
+ "identityEd25519Pub",
38890
+ "scopeDigest",
38891
+ "consent",
38892
+ "notAfter",
38893
+ "sig"
38894
+ ];
38669
38895
  KNOWN_RESPONSE_OPS = /* @__PURE__ */ new Set([
38670
38896
  ...KNOWN_CAPABILITIES,
38671
38897
  "graphql_query"
@@ -38675,7 +38901,7 @@ var init_validate = __esm({
38675
38901
 
38676
38902
  // node_modules/@fetchproxy/protocol/dist/pair-code.js
38677
38903
  async function pairTranscript(mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub) {
38678
- const label = enc2.encode(PAIR_LABEL);
38904
+ const label = enc3.encode(PAIR_LABEL);
38679
38905
  const parts = [mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub];
38680
38906
  const out = new Uint8Array(label.length + 1 + parts.reduce((n, p) => n + p.length, 0));
38681
38907
  out.set(label, 0);
@@ -38694,11 +38920,11 @@ function digits(hash2) {
38694
38920
  const s = (n % 100000000n).toString().padStart(8, "0");
38695
38921
  return `${s.slice(0, 4)}-${s.slice(4)}`;
38696
38922
  }
38697
- var enc2, PAIR_LABEL;
38923
+ var enc3, PAIR_LABEL;
38698
38924
  var init_pair_code = __esm({
38699
38925
  "node_modules/@fetchproxy/protocol/dist/pair-code.js"() {
38700
38926
  init_crypto();
38701
- enc2 = new TextEncoder();
38927
+ enc3 = new TextEncoder();
38702
38928
  PAIR_LABEL = "fetchproxy/4/pair";
38703
38929
  }
38704
38930
  });
@@ -38713,14 +38939,14 @@ function base64Length(byteLength) {
38713
38939
  return Math.ceil(byteLength / 3) * 4;
38714
38940
  }
38715
38941
  function encodeInnerFrame(inner) {
38716
- return enc3.encode(JSON.stringify(inner));
38942
+ return enc4.encode(JSON.stringify(inner));
38717
38943
  }
38718
38944
  function plaintextOf(inner) {
38719
38945
  return inner instanceof Uint8Array ? inner : encodeInnerFrame(inner);
38720
38946
  }
38721
38947
  function sealedFrameWireBytes(mcpId, seq, inner) {
38722
38948
  const plaintext = plaintextOf(inner).length;
38723
- const envelope = enc3.encode(JSON.stringify({ type: "frame", mcpId, seq, iv: "", ciphertext: "" })).length;
38949
+ const envelope = enc4.encode(JSON.stringify({ type: "frame", mcpId, seq, iv: "", ciphertext: "" })).length;
38724
38950
  return envelope + IV_B64_BYTES + base64Length(plaintext + AES_GCM_TAG_BYTES);
38725
38951
  }
38726
38952
  async function sealInnerFrame(sessionKey, mcpId, seq, inner, direction) {
@@ -38758,14 +38984,14 @@ async function openEncryptedFrameDetailed(sessionKey, frame, direction) {
38758
38984
  return { stage: "validation-failed", error: error62, recoveredId };
38759
38985
  }
38760
38986
  }
38761
- var enc3, dec, AES_GCM_TAG_BYTES, IV_B64_BYTES, MAX_FRAME_BYTES;
38987
+ var enc4, dec, AES_GCM_TAG_BYTES, IV_B64_BYTES, MAX_FRAME_BYTES;
38762
38988
  var init_seal = __esm({
38763
38989
  "node_modules/@fetchproxy/protocol/dist/seal.js"() {
38764
38990
  init_crypto();
38765
38991
  init_encoding();
38766
38992
  init_frames();
38767
38993
  init_validate();
38768
- enc3 = new TextEncoder();
38994
+ enc4 = new TextEncoder();
38769
38995
  dec = new TextDecoder();
38770
38996
  AES_GCM_TAG_BYTES = 16;
38771
38997
  IV_B64_BYTES = 16;
@@ -38777,6 +39003,8 @@ var init_seal = __esm({
38777
39003
  var init_dist3 = __esm({
38778
39004
  "node_modules/@fetchproxy/protocol/dist/index.js"() {
38779
39005
  init_frames();
39006
+ init_account_attest();
39007
+ init_awaiting_approval();
38780
39008
  init_capability_availability();
38781
39009
  init_validate();
38782
39010
  init_crypto();
@@ -42815,14 +43043,23 @@ var init_session_ready = __esm({
42815
43043
  platform;
42816
43044
  /**
42817
43045
  * #418: the remedy, when the reason is one this package knows how to
42818
- * explain — today only `unsupported-capability`, which blames the browser
42819
- * rather than the MCP. `null` otherwise.
43046
+ * explain — `unsupported-capability`, which blames the browser rather than
43047
+ * the MCP, and (D12) `awaiting-approval`, which says to approve in the
43048
+ * browser. `null` otherwise.
42820
43049
  */
42821
43050
  hint;
43051
+ /**
43052
+ * D12: `true` only for an `awaiting-approval:` refusal — the extension has
43053
+ * queued an approval card and nobody is at the browser yet, so the same call
43054
+ * succeeds once the person approves. Every other refusal is the extension's
43055
+ * final answer, and retrying unchanged is refused the same way.
43056
+ */
43057
+ retryable;
42822
43058
  constructor(info) {
42823
43059
  const unavailable = parseUnsupportedCapabilityReason(info.reason);
43060
+ const awaiting = parseAwaitingApprovalReason(info.reason);
42824
43061
  const platform = info.platform ?? null;
42825
- const hint = unavailable !== null ? `${platform ? `this browser (${platform})` : "this browser"} cannot serve any of the capabilities this MCP needs (${unavailable.join(", ")}) \u2014 ContextMint Bridge checked for the browser APIs and they are missing. Nothing is wrong with the MCP or your pairing, and updating will not change it: use this MCP from a browser that provides them (for example Chrome).` : null;
43062
+ const hint = awaiting !== null ? `The extension is waiting for you to approve this MCP` + (awaiting !== "" ? ` (${awaiting})` : "") + ` \u2014 open ContextMint Bridge in your browser, approve it there, then retry. Nothing is wrong with the MCP or your sign-in.` : unavailable !== null ? `${platform ? `this browser (${platform})` : "this browser"} cannot serve any of the capabilities this MCP needs (${unavailable.join(", ")}) \u2014 ContextMint Bridge checked for the browser APIs and they are missing. Nothing is wrong with the MCP or your pairing, and updating will not change it: use this MCP from a browser that provides them (for example Chrome).` : null;
42826
43063
  super(`fetchproxy: the extension refused the connection for "${info.mcpId}": ${info.reason}. ` + (hint !== null ? hint : `This is the extension's own reason \u2014 it is not a timeout, and retrying unchanged will be refused the same way.`));
42827
43064
  this.name = "FetchproxyHelloRejectedError";
42828
43065
  this.mcpId = info.mcpId;
@@ -42830,6 +43067,7 @@ var init_session_ready = __esm({
42830
43067
  this.unavailableCapabilities = unavailable ?? [];
42831
43068
  this.platform = platform;
42832
43069
  this.hint = hint;
43070
+ this.retryable = awaiting !== null;
42833
43071
  Object.setPrototypeOf(this, new.target.prototype);
42834
43072
  }
42835
43073
  };
@@ -43442,10 +43680,20 @@ async function startHost(opts) {
43442
43680
  let resolveOwnSession;
43443
43681
  let rejectOwnSession;
43444
43682
  let ownSessionReady;
43683
+ let ownRetryableRefusal = false;
43684
+ let ownSessionSettled = false;
43445
43685
  function resetSessionPromise() {
43686
+ ownRetryableRefusal = false;
43687
+ ownSessionSettled = false;
43446
43688
  ownSessionReady = new Promise((resolve2, reject) => {
43447
- resolveOwnSession = resolve2;
43448
- rejectOwnSession = reject;
43689
+ resolveOwnSession = (st) => {
43690
+ ownSessionSettled = true;
43691
+ resolve2(st);
43692
+ };
43693
+ rejectOwnSession = (e) => {
43694
+ ownSessionSettled = true;
43695
+ reject(e);
43696
+ };
43449
43697
  });
43450
43698
  ownSessionReady.catch(() => {
43451
43699
  });
@@ -43712,13 +43960,15 @@ async function startHost(opts) {
43712
43960
  const extPub = fromB64(frame.extensionSessionPub);
43713
43961
  const shared = await ecdhX25519(held.priv, extPub);
43714
43962
  const salt = await transcriptHash(held.nonce, extNonce, held.pub, extPub);
43715
- const key = await hkdfSha256(shared, salt, enc4.encode(HKDF_SESSION_INFO), 32);
43963
+ const key = await hkdfSha256(shared, salt, enc5.encode(HKDF_SESSION_INFO), 32);
43716
43964
  if (extensionWs !== ws)
43717
43965
  return;
43718
43966
  ownSession = new SessionState(key);
43719
43967
  ownSessionInfo = sessionInfoFromHello(verifiedHello);
43720
43968
  ownDecryptFailures = 0;
43721
43969
  ownPendingPairCode = null;
43970
+ if (ownRetryableRefusal)
43971
+ resetSessionPromise();
43722
43972
  resolveOwnSession(ownSession);
43723
43973
  } else {
43724
43974
  const slot = peers.get(frame.mcpId);
@@ -43787,11 +44037,17 @@ async function startHost(opts) {
43787
44037
  }
43788
44038
  if (frame.type === "hello-rejected" && identified === "extension") {
43789
44039
  if (frame.mcpId === opts.ownMcpId) {
43790
- rejectOwnSession(new FetchproxyHelloRejectedError({
44040
+ const refusal = new FetchproxyHelloRejectedError({
43791
44041
  mcpId: frame.mcpId,
43792
44042
  reason: frame.reason,
43793
44043
  platform: extensionHello?.platform ?? null
43794
- }));
44044
+ });
44045
+ if (ownRetryableRefusal)
44046
+ resetSessionPromise();
44047
+ const settlesPending = !ownSessionSettled;
44048
+ rejectOwnSession(refusal);
44049
+ if (refusal.retryable && settlesPending)
44050
+ ownRetryableRefusal = true;
43795
44051
  } else {
43796
44052
  const slot = peers.get(frame.mcpId);
43797
44053
  if (slot?.helloFrame.accepts?.includes("hello-rejected")) {
@@ -43904,7 +44160,7 @@ async function startHost(opts) {
43904
44160
  sessionInfo: () => ownSession !== null ? ownSessionInfo : null
43905
44161
  };
43906
44162
  }
43907
- var HTTP_ORIGIN_RE, PUBLIC_ORIGIN_RE, EXTENSION_ORIGIN_RE, OPAQUE_ORIGIN, ALLOW_LOCAL_ORIGINS_ENV, HANDSHAKE_TIMEOUT_MS, MAX_PAYLOAD_BYTES, enc4, OWN_DECRYPT_FAILURES_BEFORE_REHANDSHAKE;
44163
+ var HTTP_ORIGIN_RE, PUBLIC_ORIGIN_RE, EXTENSION_ORIGIN_RE, OPAQUE_ORIGIN, ALLOW_LOCAL_ORIGINS_ENV, HANDSHAKE_TIMEOUT_MS, MAX_PAYLOAD_BYTES, enc5, OWN_DECRYPT_FAILURES_BEFORE_REHANDSHAKE;
43908
44164
  var init_host = __esm({
43909
44165
  "node_modules/@fetchproxy/server/dist/host.js"() {
43910
44166
  init_wrapper();
@@ -43923,7 +44179,7 @@ var init_host = __esm({
43923
44179
  ALLOW_LOCAL_ORIGINS_ENV = "FETCHPROXY_ALLOW_LOCAL_ORIGINS";
43924
44180
  HANDSHAKE_TIMEOUT_MS = 15e3;
43925
44181
  MAX_PAYLOAD_BYTES = MAX_FRAME_BYTES;
43926
- enc4 = new TextEncoder();
44182
+ enc5 = new TextEncoder();
43927
44183
  OWN_DECRYPT_FAILURES_BEFORE_REHANDSHAKE = 3;
43928
44184
  }
43929
44185
  });
@@ -44028,7 +44284,9 @@ async function startPeer(opts) {
44028
44284
  let rejectFirstReady;
44029
44285
  let sessionPromise;
44030
44286
  let sessionPromiseSettled = false;
44287
+ let retryableRefusal = false;
44031
44288
  function resetSessionPromise() {
44289
+ retryableRefusal = false;
44032
44290
  sessionPromiseSettled = false;
44033
44291
  sessionPromise = new Promise((resolve2, reject) => {
44034
44292
  resolveFirstReady = (st) => {
@@ -44125,6 +44383,8 @@ async function startPeer(opts) {
44125
44383
  raw = JSON.parse(data.toString());
44126
44384
  const frame = validateFrame(raw);
44127
44385
  if (frame.type === "hello" && frame.role === "extension") {
44386
+ if (retryableRefusal)
44387
+ resetSessionPromise();
44128
44388
  extensionHello = frame;
44129
44389
  const mintedKeypair = await generateSessionKeypair();
44130
44390
  const mintedHello = await buildServerHello({
@@ -44154,6 +44414,8 @@ async function startPeer(opts) {
44154
44414
  session = null;
44155
44415
  if (sessionPromiseSettled)
44156
44416
  resetSessionPromise();
44417
+ } else if (retryableRefusal) {
44418
+ resetSessionPromise();
44157
44419
  }
44158
44420
  extensionDisconnectListeners.forEach((cb) => cb());
44159
44421
  return;
@@ -44175,7 +44437,7 @@ async function startPeer(opts) {
44175
44437
  const extNonce = fromB64(authenticated.sessionNonce);
44176
44438
  const shared = await ecdhX25519(held.priv, extPub);
44177
44439
  const salt = await transcriptHash(held.nonce, extNonce, held.pub, extPub);
44178
- const sessionKey = await hkdfSha256(shared, salt, enc5.encode(HKDF_SESSION_INFO), 32);
44440
+ const sessionKey = await hkdfSha256(shared, salt, enc6.encode(HKDF_SESSION_INFO), 32);
44179
44441
  if (sessionEphemeral !== held) {
44180
44442
  console.warn(`[fetchproxy] ${opts.serverName}: dropping a session derived against an ephemeral that was superseded while it was being derived`);
44181
44443
  return;
@@ -44188,16 +44450,24 @@ async function startPeer(opts) {
44188
44450
  if (isRenegotiation) {
44189
44451
  renegotiateListeners.forEach((cb) => cb());
44190
44452
  } else {
44453
+ if (retryableRefusal)
44454
+ resetSessionPromise();
44191
44455
  resolveFirstReady(session);
44192
44456
  }
44193
44457
  return;
44194
44458
  }
44195
44459
  if (frame.type === "hello-rejected" && frame.mcpId === opts.mcpId) {
44196
- rejectFirstReady(new FetchproxyHelloRejectedError({
44460
+ const refusal = new FetchproxyHelloRejectedError({
44197
44461
  mcpId: frame.mcpId,
44198
44462
  reason: frame.reason,
44199
44463
  platform: extensionHello?.platform ?? null
44200
- }));
44464
+ });
44465
+ if (retryableRefusal)
44466
+ resetSessionPromise();
44467
+ const settlesPending = !sessionPromiseSettled;
44468
+ rejectFirstReady(refusal);
44469
+ if (refusal.retryable && settlesPending)
44470
+ retryableRefusal = true;
44201
44471
  }
44202
44472
  if (frame.type === "pair-pending" && frame.mcpId === opts.mcpId) {
44203
44473
  const hello2 = extensionHello;
@@ -44327,7 +44597,7 @@ async function startPeer(opts) {
44327
44597
  };
44328
44598
  return handle;
44329
44599
  }
44330
- var PEER_DIAL_TIMEOUT_MS, enc5;
44600
+ var PEER_DIAL_TIMEOUT_MS, enc6;
44331
44601
  var init_peer = __esm({
44332
44602
  "node_modules/@fetchproxy/server/dist/peer.js"() {
44333
44603
  init_wrapper();
@@ -44341,7 +44611,7 @@ var init_peer = __esm({
44341
44611
  init_extension_trust();
44342
44612
  init_extension_pins();
44343
44613
  PEER_DIAL_TIMEOUT_MS = 5e3;
44344
- enc5 = new TextEncoder();
44614
+ enc6 = new TextEncoder();
44345
44615
  }
44346
44616
  });
44347
44617
 
@@ -44383,8 +44653,9 @@ var init_error_kind = __esm({
44383
44653
 
44384
44654
  // node_modules/@fetchproxy/server/dist/classify-bridge-error.js
44385
44655
  function classifyBridgeError(err) {
44386
- if (err instanceof FetchproxyHelloRejectedError)
44387
- return "hello_rejected";
44656
+ if (err instanceof FetchproxyHelloRejectedError) {
44657
+ return err.retryable ? "awaiting_approval" : "hello_rejected";
44658
+ }
44388
44659
  if (err instanceof FetchproxySessionNotReadyError)
44389
44660
  return "session_not_ready";
44390
44661
  if (err instanceof FetchproxyTimeoutError)
@@ -48796,7 +49067,7 @@ await runMcp({
48796
49067
  });
48797
49068
  /*! Bundled license information:
48798
49069
 
48799
- @modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs:
49070
+ @modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs:
48800
49071
  (*!
48801
49072
  * content-type
48802
49073
  * Copyright(c) 2015 Douglas Christopher Wilson
package/dist/version.js CHANGED
@@ -10,4 +10,4 @@
10
10
  * line below and nowhere else — not even in prose.
11
11
  */
12
12
  export const PACKAGE_NAME = 'office-outlook-mcp';
13
- export const VERSION = '0.3.3'; // x-release-please-version
13
+ export const VERSION = '0.3.4'; // x-release-please-version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrischall/office-outlook-mcp",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
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,14 +45,14 @@
45
45
  "typecheck": "tsc -p tsconfig.check.json"
46
46
  },
47
47
  "dependencies": {
48
- "@chrischall/mcp-utils": "^2.13.0",
48
+ "@chrischall/mcp-utils": "^2.14.0",
49
49
  "@fetchproxy/server": "^3.4.1",
50
- "@modelcontextprotocol/server": "^2.2.0",
50
+ "@modelcontextprotocol/server": "^2.3.0",
51
51
  "dotenv": "^18.0.1",
52
52
  "zod": "^4.6.5"
53
53
  },
54
54
  "devDependencies": {
55
- "@modelcontextprotocol/client": "^2.2.0",
55
+ "@modelcontextprotocol/client": "^2.3.0",
56
56
  "@types/node": "^26.0.0",
57
57
  "@vitest/coverage-v8": "^5.0.0",
58
58
  "esbuild": "^0.28.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.3.3",
9
+ "version": "0.3.4",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@chrischall/office-outlook-mcp",
14
- "version": "0.3.3",
14
+ "version": "0.3.4",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },