@chrischall/office-outlook-mcp 0.3.4 → 0.3.5

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.4"
10
+ "version": "0.3.5"
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.4",
18
+ "version": "0.3.5",
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.4",
4
+ "version": "0.3.5",
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/README.md CHANGED
@@ -148,7 +148,8 @@ a fresh preview.
148
148
 
149
149
  | variable | default | |
150
150
  |---|---|---|
151
- | `MCP_CONFIRM_MODE` | `ask-user` | What a write does on a client that cannot show a confirmation prompt (claude.ai, Claude Desktop). `ask-user`: two steps — the first call does nothing and returns a preview plus a token, and the model must get your approval in chat before calling again with it. `auto`: the same two steps, but the model may use the token after reviewing the preview itself. `refuse`: writes are refused on such clients. A client that can show prompts (Claude Code) always gets the real prompt. An unrecognised value is treated as `refuse`. |
151
+ | `MCP_CONFIRM_MODE` | `ask-user` | What a write does on a client that cannot show a confirmation prompt (claude.ai, Claude Desktop). `ask-user`: two steps — the first call does nothing and returns a preview plus a token, and the model must get your approval in chat before calling again with it. `auto`: the same two steps, but the model may use the token after reviewing the preview itself. `refuse`: writes are refused on such clients. A client that can show prompts (Claude Code) always gets the real prompt, unless `MCP_CONFIRM_ELICITATION=off`. An unrecognised value is treated as `refuse`. |
152
+ | `MCP_CONFIRM_ELICITATION` | `on` | `off` never shows a confirmation prompt, so every client gets the `MCP_CONFIRM_MODE` behaviour. Set it for a client that says it can show prompts but never does (the write hangs — opencode 2.0.x). Any other value is treated as `on`, with a warning on stderr. |
152
153
  | `MCP_CONFIRM_TTL_SECONDS` | `600` | How long a token stays valid. |
153
154
  | `MCP_CONFIRM_SECRET` | random per process | Signing key; set it only if tokens must survive a server restart. On mcp-host the host supplies a stable per-child key (`MCP_HOST_CONFIRM_SECRET`) and spent tokens are recorded under `MCP_DATA_DIR`, so an approval survives an idle restart. |
154
155
 
package/dist/bundle.js CHANGED
@@ -35663,6 +35663,15 @@ ${JSON.stringify(preview, null, 2)}`,
35663
35663
  };
35664
35664
  const response = inputResponse(ctx.mcpReq.inputResponses, requestKey);
35665
35665
  const accepted = acceptedContent(ctx.mcpReq.inputResponses, requestKey, confirmationSchema);
35666
+ if (options.elicitation === false) {
35667
+ return textResult({
35668
+ confirmed: false,
35669
+ dispatched: false,
35670
+ action: options.action,
35671
+ reason: "confirmation-unsupported",
35672
+ note: options.unsupportedNote ? `${DISABLED_NOTE}. ${options.unsupportedNote}` : `${DISABLED_NOTE}.`
35673
+ });
35674
+ }
35666
35675
  if (response.kind === "missing") {
35667
35676
  if (callerAcceptsFormElicitation(ctx) === false) {
35668
35677
  return textResult({
@@ -35693,7 +35702,7 @@ ${JSON.stringify(preview, null, 2)}`,
35693
35702
  note: "Nothing was changed because the confirmation was declined, cancelled, or left unchecked."
35694
35703
  });
35695
35704
  }
35696
- var DEFAULT_REQUEST_KEY, DEFAULT_CONFIRMATION_LABEL, UNSUPPORTED_NOTE, STATE_PREFIX;
35705
+ var DEFAULT_REQUEST_KEY, DEFAULT_CONFIRMATION_LABEL, UNSUPPORTED_NOTE, DISABLED_NOTE, STATE_PREFIX;
35697
35706
  var init_confirmation = __esm({
35698
35707
  "node_modules/@chrischall/mcp-utils/dist/server/confirmation.js"() {
35699
35708
  init_dist();
@@ -35704,6 +35713,7 @@ var init_confirmation = __esm({
35704
35713
  DEFAULT_REQUEST_KEY = "confirmation";
35705
35714
  DEFAULT_CONFIRMATION_LABEL = "Confirm this action should proceed.";
35706
35715
  UNSUPPORTED_NOTE = "Nothing was done because this client cannot show a confirmation prompt (it declares no MCP elicitation capability), and this action is never taken without one";
35716
+ DISABLED_NOTE = "Nothing was done because confirmation prompts are turned off for this server, and this action is never taken without one";
35707
35717
  STATE_PREFIX = "mcpu.confirm.v1.";
35708
35718
  }
35709
35719
  });
@@ -35857,7 +35867,7 @@ async function tokenConfirmation(action, fb) {
35857
35867
  }
35858
35868
  async function requireConfirmationWithFallback(ctx, options) {
35859
35869
  const { tokenFallback, ...confirmation } = options;
35860
- if (tokenFallback && callerAcceptsFormElicitation(ctx) === false) {
35870
+ if (tokenFallback && (options.elicitation === false || callerAcceptsFormElicitation(ctx) === false)) {
35861
35871
  return tokenConfirmation(options.action, tokenFallback);
35862
35872
  }
35863
35873
  return requireConfirmation(ctx, confirmation);
@@ -36068,6 +36078,20 @@ function readConfirmMode(env = process.env) {
36068
36078
  }
36069
36079
  return "refuse";
36070
36080
  }
36081
+ function readConfirmElicitation(env = process.env) {
36082
+ const raw = readEnvVar("MCP_CONFIRM_ELICITATION", { env })?.trim().toLowerCase();
36083
+ if (!raw || raw === "on")
36084
+ return "on";
36085
+ if (raw === "off")
36086
+ return "off";
36087
+ const key = `elicitation:${raw}`;
36088
+ if (!warned.has(key)) {
36089
+ warned.add(key);
36090
+ process.stderr.write(`MCP_CONFIRM_ELICITATION="${raw}" is not one of on, off; treating it as on.
36091
+ `);
36092
+ }
36093
+ return "on";
36094
+ }
36071
36095
  function readConfirmTtl(env) {
36072
36096
  const raw = readEnvVar("MCP_CONFIRM_TTL_SECONDS", { env })?.trim();
36073
36097
  if (!raw)
@@ -36120,10 +36144,13 @@ function confirmationFromEnv(options) {
36120
36144
  const spent = callerSpent ?? spentTokenStoreFromEnv(env);
36121
36145
  const mode = readConfirmMode(env);
36122
36146
  const ttlSeconds = readConfirmTtl(env);
36147
+ const elicitationOff = readConfirmElicitation(env) === "off";
36123
36148
  const bound = args === void 0 ? void 0 : boundArgs(args);
36124
- const confirmation = bound === void 0 || rest.binding ? rest : { ...rest, binding: { key: confirmKeyFromEnv(env), args: bound, ttlSeconds: ttlSeconds ?? DEFAULT_TTL_SECONDS2 } };
36149
+ const bindingAdded = bound === void 0 || rest.binding ? rest : { ...rest, binding: { key: confirmKeyFromEnv(env), args: bound, ttlSeconds: ttlSeconds ?? DEFAULT_TTL_SECONDS2 } };
36150
+ const confirmation = elicitationOff ? { ...bindingAdded, elicitation: false } : bindingAdded;
36125
36151
  if (mode === "refuse" || ttlSeconds === void 0) {
36126
- const hint = mode === "refuse" ? REFUSE_HINT : BAD_TTL_HINT;
36152
+ const reason = mode === "refuse" ? REFUSE_HINT : BAD_TTL_HINT;
36153
+ const hint = elicitationOff ? `${ELICITATION_OFF_HINT} ${reason}` : reason;
36127
36154
  return {
36128
36155
  ...confirmation,
36129
36156
  unsupportedNote: confirmation.unsupportedNote ? `${confirmation.unsupportedNote} ${hint}` : hint
@@ -36149,7 +36176,7 @@ function confirmationFromEnv(options) {
36149
36176
  }
36150
36177
  };
36151
36178
  }
36152
- var MODES, DEFAULT_TTL_SECONDS2, warned, processKey, fileStores, CONFIRM_TOKEN_AUTO_INSTRUCTION, REFUSE_HINT, BAD_TTL_HINT;
36179
+ var MODES, DEFAULT_TTL_SECONDS2, warned, processKey, fileStores, CONFIRM_TOKEN_AUTO_INSTRUCTION, REFUSE_HINT, ELICITATION_OFF_HINT, BAD_TTL_HINT;
36153
36180
  var init_confirm_env = __esm({
36154
36181
  "node_modules/@chrischall/mcp-utils/dist/server/confirm-env.js"() {
36155
36182
  init_config();
@@ -36161,6 +36188,7 @@ var init_confirm_env = __esm({
36161
36188
  fileStores = /* @__PURE__ */ new Map();
36162
36189
  CONFIRM_TOKEN_AUTO_INSTRUCTION = "Nothing has been done yet. Review this preview; if it is what was intended, call again with the same arguments plus confirmToken. (This server runs with MCP_CONFIRM_MODE=auto, so the user's approval in chat is not required.)";
36163
36190
  REFUSE_HINT = "Set MCP_CONFIRM_MODE=ask-user on the server to allow two-step confirmation instead.";
36191
+ ELICITATION_OFF_HINT = "MCP_CONFIRM_ELICITATION=off on the server turns confirmation prompts off.";
36164
36192
  BAD_TTL_HINT = "MCP_CONFIRM_TTL_SECONDS on the server is not a positive whole number of seconds; fix it to allow two-step confirmation.";
36165
36193
  }
36166
36194
  });
@@ -37120,7 +37148,7 @@ var init_version = __esm({
37120
37148
  "src/version.ts"() {
37121
37149
  "use strict";
37122
37150
  PACKAGE_NAME = "office-outlook-mcp";
37123
- VERSION = "0.3.4";
37151
+ VERSION = "0.3.5";
37124
37152
  }
37125
37153
  });
37126
37154
 
@@ -37372,7 +37400,7 @@ async function transcriptHash(mcpNonce, extNonce, mcpSessionPub, extSessionPub)
37372
37400
  function frameAad(mcpId, seq, direction) {
37373
37401
  return enc.encode(`fetchproxy/4/frame\0${mcpId}\0${seq}\0${direction}`);
37374
37402
  }
37375
- var PROTOCOL_VERSION, HKDF_SESSION_INFO, enc, ANSWERS_NO_EXT_SESSION, KNOWN_CAPABILITIES, ACCOUNT_KEY_FRAME, ACCOUNT_ATTEST_FRAME;
37403
+ var PROTOCOL_VERSION, HKDF_SESSION_INFO, enc, ANSWERS_NO_EXT_SESSION, KNOWN_CAPABILITIES, ACCOUNT_KEY_FRAME, ACCOUNT_ATTEST_FRAME, BRIDGE_ROLE_FRAME, BRIDGE_SERVE_FRAME, ROOM_PING_FRAME, ROOM_PONG_FRAME, BRIDGE_ROLE_LABEL_MAX, ROOM_FRAME_ACCEPTS;
37376
37404
  var init_frames = __esm({
37377
37405
  "node_modules/@fetchproxy/protocol/dist/frames.js"() {
37378
37406
  init_crypto();
@@ -37398,6 +37426,17 @@ var init_frames = __esm({
37398
37426
  ]);
37399
37427
  ACCOUNT_KEY_FRAME = "account-key";
37400
37428
  ACCOUNT_ATTEST_FRAME = "account-attest";
37429
+ BRIDGE_ROLE_FRAME = "bridge-role";
37430
+ BRIDGE_SERVE_FRAME = "bridge-serve";
37431
+ ROOM_PING_FRAME = "room-ping";
37432
+ ROOM_PONG_FRAME = "room-pong";
37433
+ BRIDGE_ROLE_LABEL_MAX = 64;
37434
+ ROOM_FRAME_ACCEPTS = Object.freeze({
37435
+ [BRIDGE_ROLE_FRAME]: BRIDGE_ROLE_FRAME,
37436
+ [BRIDGE_SERVE_FRAME]: BRIDGE_SERVE_FRAME,
37437
+ [ROOM_PING_FRAME]: ROOM_PING_FRAME,
37438
+ [ROOM_PONG_FRAME]: ROOM_PING_FRAME
37439
+ });
37401
37440
  }
37402
37441
  });
37403
37442
 
@@ -38081,6 +38120,12 @@ function validateFrame(raw) {
38081
38120
  return validateAccountKey(raw);
38082
38121
  if (t === ACCOUNT_ATTEST_FRAME)
38083
38122
  return validateAccountAttest(raw);
38123
+ if (t === BRIDGE_ROLE_FRAME)
38124
+ return validateBridgeRole(raw);
38125
+ if (t === BRIDGE_SERVE_FRAME || t === ROOM_PING_FRAME || t === ROOM_PONG_FRAME) {
38126
+ assertExactFields(raw, TYPE_ONLY_FIELDS, t);
38127
+ return { type: t };
38128
+ }
38084
38129
  throw new ProtocolError3(`unknown frame type: ${String(t)}`);
38085
38130
  }
38086
38131
  function validateHello(raw) {
@@ -38376,6 +38421,40 @@ function validateAccountAttest(raw) {
38376
38421
  sig: raw.sig
38377
38422
  };
38378
38423
  }
38424
+ function validateBridgeRole(raw) {
38425
+ const L = BRIDGE_ROLE_FRAME;
38426
+ const role = raw.role;
38427
+ if (role !== "serving" && role !== "standby") {
38428
+ throw new ProtocolError3(`${L}.role: must be one of serving, standby`);
38429
+ }
38430
+ const canServe = raw.canServe;
38431
+ assertBoolean(canServe, `${L}.canServe`);
38432
+ assertExactFields(raw, BRIDGE_ROLE_FIELDS, L);
38433
+ const serving = raw.serving;
38434
+ if (role === "serving") {
38435
+ if (serving !== void 0) {
38436
+ throw new ProtocolError3(`${L}.serving: must be absent when role is serving`);
38437
+ }
38438
+ return { type: BRIDGE_ROLE_FRAME, role, canServe };
38439
+ }
38440
+ if (serving === void 0) {
38441
+ throw new ProtocolError3(`${L}.serving: required when role is standby`);
38442
+ }
38443
+ assertObject(serving, `${L}.serving`);
38444
+ const label = serving.label;
38445
+ assertDisplayString(label, `${L}.serving.label`, 1, BRIDGE_ROLE_LABEL_MAX);
38446
+ const since = serving.since;
38447
+ if (typeof since !== "number" || !Number.isSafeInteger(since) || since < 0) {
38448
+ throw new ProtocolError3(`${L}.serving.since: expected non-negative safe integer (Unix ms)`);
38449
+ }
38450
+ assertExactFields(serving, BRIDGE_ROLE_SERVING_FIELDS, `${L}.serving`);
38451
+ return {
38452
+ type: BRIDGE_ROLE_FRAME,
38453
+ role,
38454
+ canServe,
38455
+ serving: { label, since }
38456
+ };
38457
+ }
38379
38458
  function validateInnerFrame(raw) {
38380
38459
  assertObject(raw, "inner");
38381
38460
  const t = raw.type;
@@ -38837,7 +38916,7 @@ function validateInnerResponse(raw) {
38837
38916
  }
38838
38917
  throw new ProtocolError3(`inner.ok: must be boolean, got ${typeof raw.ok}`);
38839
38918
  }
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;
38919
+ 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, TYPE_ONLY_FIELDS, BRIDGE_ROLE_FIELDS, BRIDGE_ROLE_SERVING_FIELDS, KNOWN_RESPONSE_OPS;
38841
38920
  var init_validate = __esm({
38842
38921
  "node_modules/@fetchproxy/protocol/dist/validate.js"() {
38843
38922
  init_frames();
@@ -38892,6 +38971,9 @@ var init_validate = __esm({
38892
38971
  "notAfter",
38893
38972
  "sig"
38894
38973
  ];
38974
+ TYPE_ONLY_FIELDS = ["type"];
38975
+ BRIDGE_ROLE_FIELDS = ["type", "role", "canServe", "serving"];
38976
+ BRIDGE_ROLE_SERVING_FIELDS = ["label", "since"];
38895
38977
  KNOWN_RESPONSE_OPS = /* @__PURE__ */ new Set([
38896
38978
  ...KNOWN_CAPABILITIES,
38897
38979
  "graphql_query"
@@ -38899,6 +38981,14 @@ var init_validate = __esm({
38899
38981
  }
38900
38982
  });
38901
38983
 
38984
+ // node_modules/@fetchproxy/protocol/dist/room-frames.js
38985
+ var init_room_frames = __esm({
38986
+ "node_modules/@fetchproxy/protocol/dist/room-frames.js"() {
38987
+ init_frames();
38988
+ init_validate();
38989
+ }
38990
+ });
38991
+
38902
38992
  // node_modules/@fetchproxy/protocol/dist/pair-code.js
38903
38993
  async function pairTranscript(mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub) {
38904
38994
  const label = enc3.encode(PAIR_LABEL);
@@ -39007,6 +39097,7 @@ var init_dist3 = __esm({
39007
39097
  init_awaiting_approval();
39008
39098
  init_capability_availability();
39009
39099
  init_validate();
39100
+ init_room_frames();
39010
39101
  init_crypto();
39011
39102
  init_mcp_id();
39012
39103
  init_pair_code();
@@ -41405,11 +41496,23 @@ var require_websocket = __commonJS({
41405
41496
  this._isServer = false;
41406
41497
  this._redirects = 0;
41407
41498
  if (protocols === void 0) {
41408
- protocols = [];
41499
+ if (!options || options.protocols === void 0) {
41500
+ protocols = [];
41501
+ } else if (Array.isArray(options.protocols)) {
41502
+ protocols = options.protocols;
41503
+ } else {
41504
+ protocols = [options.protocols];
41505
+ }
41409
41506
  } else if (!Array.isArray(protocols)) {
41410
41507
  if (typeof protocols === "object" && protocols !== null) {
41411
41508
  options = protocols;
41412
- protocols = [];
41509
+ if (options.protocols === void 0) {
41510
+ protocols = [];
41511
+ } else if (Array.isArray(options.protocols)) {
41512
+ protocols = options.protocols;
41513
+ } else {
41514
+ protocols = [options.protocols];
41515
+ }
41413
41516
  } else {
41414
41517
  protocols = [protocols];
41415
41518
  }
@@ -41606,7 +41709,6 @@ var require_websocket = __commonJS({
41606
41709
  }
41607
41710
  return;
41608
41711
  }
41609
- this._readyState = _WebSocket.CLOSING;
41610
41712
  this._sender.close(code2, data, !this._isServer, (err) => {
41611
41713
  if (err) return;
41612
41714
  this._closeFrameSent = true;
@@ -41614,6 +41716,7 @@ var require_websocket = __commonJS({
41614
41716
  this._socket.end();
41615
41717
  }
41616
41718
  });
41719
+ this._readyState = _WebSocket.CLOSING;
41617
41720
  setCloseTimer(this);
41618
41721
  }
41619
41722
  /**
@@ -41838,6 +41941,7 @@ var require_websocket = __commonJS({
41838
41941
  socketPath: void 0,
41839
41942
  hostname: void 0,
41840
41943
  protocol: void 0,
41944
+ protocols: void 0,
41841
41945
  timeout: void 0,
41842
41946
  method: "GET",
41843
41947
  host: void 0,
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.4'; // x-release-please-version
13
+ export const VERSION = '0.3.5'; // 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.4",
3
+ "version": "0.3.5",
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,8 +45,8 @@
45
45
  "typecheck": "tsc -p tsconfig.check.json"
46
46
  },
47
47
  "dependencies": {
48
- "@chrischall/mcp-utils": "^2.14.0",
49
- "@fetchproxy/server": "^3.4.1",
48
+ "@chrischall/mcp-utils": "^2.15.0",
49
+ "@fetchproxy/server": "^3.6.0",
50
50
  "@modelcontextprotocol/server": "^2.3.0",
51
51
  "dotenv": "^18.0.1",
52
52
  "zod": "^4.6.5"
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.4",
9
+ "version": "0.3.5",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@chrischall/office-outlook-mcp",
14
- "version": "0.3.4",
14
+ "version": "0.3.5",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },