@chrischall/office-outlook-mcp 0.8.1 → 0.8.2
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/README.md +19 -1
- package/dist/auth-fetchproxy.js +65 -57
- package/dist/bundle.js +33 -26
- package/dist/version.js +1 -1
- package/mint.yaml +10 -4
- package/package.json +1 -1
- package/server.json +8 -2
- package/skills/outlook-fpx/SKILL.md +8 -3
|
@@ -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.8.
|
|
10
|
+
"version": "0.8.2"
|
|
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.8.
|
|
18
|
+
"version": "0.8.2",
|
|
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.8.
|
|
4
|
+
"version": "0.8.2",
|
|
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/README.md
CHANGED
|
@@ -54,6 +54,23 @@ npm i -g @fetchproxy/cli
|
|
|
54
54
|
The first capture prints a 6-digit pair code to approve in the ContextMint
|
|
55
55
|
Bridge popup; the grant persists.
|
|
56
56
|
|
|
57
|
+
### Pairing
|
|
58
|
+
|
|
59
|
+
The server declares **one** host to the bridge — `outlook.cloud.microsoft`, or
|
|
60
|
+
`OUTLOOK_WEB_HOST` — and the same scope on every capture, so once approved it
|
|
61
|
+
neither re-pairs nor asks for wider grants. The bridge keeps one relay tab on
|
|
62
|
+
that host open (it reuses yours if you already have Outlook open).
|
|
63
|
+
|
|
64
|
+
Before 0.8.2 it also declared `outlook.office.com`. A signed-in tab there
|
|
65
|
+
redirects to `outlook.cloud.microsoft`, so the bridge opened another background
|
|
66
|
+
tab on every capture. Upgrading changes the declared domain set, so the bridge
|
|
67
|
+
asks to pair **once** more.
|
|
68
|
+
|
|
69
|
+
If you run the bridge in more than one browser or browser profile, each one is a
|
|
70
|
+
different extension identity, and the server trusts only the one it paired
|
|
71
|
+
with. Keep the bridge enabled in the browser you pair with (or re-pair
|
|
72
|
+
deliberately with `FETCHPROXY_TRUST_NEW_EXTENSION=1` after switching browsers).
|
|
73
|
+
|
|
57
74
|
### Install in opencode
|
|
58
75
|
|
|
59
76
|
opencode reads MCP servers from `opencode.json` (project) or
|
|
@@ -100,7 +117,8 @@ Everything is optional — with nothing set, the server captures from the browse
|
|
|
100
117
|
| `OUTLOOK_DISABLE_FETCHPROXY` | `1` to disable browser capture, requiring `OUTLOOK_ACCESS_TOKEN`. |
|
|
101
118
|
| `OUTLOOK_API_BASE` | Override the REST base URL. Defaults to `https://outlook.office.com/api/v2.0`. |
|
|
102
119
|
| `OUTLOOK_WS_PORT` | fetchproxy concentrator port. Defaults to `37149`, the fleet-wide shared port. |
|
|
103
|
-
| `
|
|
120
|
+
| `OUTLOOK_WEB_HOST` | Which Outlook Web host your signed-in tab is on: `outlook.cloud.microsoft` (default) or `outlook.office.com` for a tenant still on the legacy app. Only this one host is declared to the bridge — see [Pairing](#pairing). |
|
|
121
|
+
| `OUTLOOK_CAPTURE_TIMEOUT` | Seconds to wait for the tab to make a readable request. Defaults to `30`. |
|
|
104
122
|
| `OUTLOOK_TOKEN_CACHE` | `false` to stop caching the token between runs. |
|
|
105
123
|
| `OUTLOOK_TOKEN_FILE` | Path to the cached token. Defaults to `~/.office-outlook-mcp/token.json`. |
|
|
106
124
|
| `OUTLOOK_OUTPUT_DIR` | Absolute directory `outlook_export_messages` and `outlook_export_events` write into. Defaults to `~/Downloads/office-outlook-mcp`. When set, a per-call `dest` must be inside it. See [Bulk export](#bulk-export). |
|
package/dist/auth-fetchproxy.js
CHANGED
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
* domain), but the token it carries has `aud: https://outlook.office.com`;
|
|
16
16
|
* - that token authenticates plain server-side requests to
|
|
17
17
|
* `outlook.office.com/api/v2.0` with no bridge involved;
|
|
18
|
-
* - older tenants still serve the app from `outlook.office.com
|
|
19
|
-
*
|
|
18
|
+
* - older tenants still serve the app from `outlook.office.com`; those set
|
|
19
|
+
* `OUTLOOK_WEB_HOST=outlook.office.com`. Only ONE host is ever declared —
|
|
20
|
+
* see `captureHost` for why.
|
|
20
21
|
*
|
|
21
22
|
* We do NOT try to mint a token by calling an endpoint ourselves. There is no
|
|
22
23
|
* such endpoint reachable from the page's origin — the token comes from MSAL's
|
|
@@ -24,19 +25,10 @@
|
|
|
24
25
|
* cannot drive. Capture is the only path, which is why a failed capture is a
|
|
25
26
|
* hard error with actionable guidance rather than a fallback.
|
|
26
27
|
*/
|
|
27
|
-
import { captureBearerHeader } from '@chrischall/mcp-utils/fetchproxy';
|
|
28
|
-
import { readPortEnv, readTtlMsEnv } from '@chrischall/mcp-utils';
|
|
28
|
+
import { captureBearerHeader, createFetchproxyTransport } from '@chrischall/mcp-utils/fetchproxy';
|
|
29
|
+
import { readEnvVar, readPortEnv, readTtlMsEnv } from '@chrischall/mcp-utils';
|
|
29
30
|
import { PACKAGE_NAME, VERSION } from './version.js';
|
|
30
|
-
|
|
31
|
-
* `raceCaptures` settles the per-host attempts under ONE overall deadline:
|
|
32
|
-
* `Promise.any` alone is not enough, because the bridge serializes the two
|
|
33
|
-
* hosts behind its single connection, so the wait was the sum rather than the
|
|
34
|
-
* max — measured live at 14.4s for a 5s window and 36s for a 20s one. At the
|
|
35
|
-
* 30s default that lands past the 60s request timeout an MCP client uses by
|
|
36
|
-
* default. Re-exported (it is mcp-utils', lifted from here) for the test that
|
|
37
|
-
* pins that bound.
|
|
38
|
-
*/
|
|
39
|
-
export { raceCaptures, stripBearer } from '@chrischall/mcp-utils/fetchproxy';
|
|
31
|
+
export { stripBearer } from '@chrischall/mcp-utils/fetchproxy';
|
|
40
32
|
/**
|
|
41
33
|
* The fetchproxy concentrator port.
|
|
42
34
|
*
|
|
@@ -51,42 +43,49 @@ export { raceCaptures, stripBearer } from '@chrischall/mcp-utils/fetchproxy';
|
|
|
51
43
|
* instead of handing `NaN` to the server.
|
|
52
44
|
*/
|
|
53
45
|
const DEFAULT_WS_PORT = 37_149;
|
|
54
|
-
export function getWsPort() {
|
|
55
|
-
return readPortEnv('OUTLOOK_WS_PORT', DEFAULT_WS_PORT);
|
|
46
|
+
export function getWsPort(env = process.env) {
|
|
47
|
+
return readPortEnv('OUTLOOK_WS_PORT', DEFAULT_WS_PORT, { env });
|
|
56
48
|
}
|
|
57
|
-
/** New Outlook Web. This is where a current tenant's tab actually lives. */
|
|
58
|
-
const CAPTURE_DECL_CLOUD = {
|
|
59
|
-
host: 'outlook.cloud.microsoft',
|
|
60
|
-
path: '/*',
|
|
61
|
-
headerName: 'authorization',
|
|
62
|
-
};
|
|
63
|
-
/** Legacy host, still serving the app for tenants not yet migrated. */
|
|
64
|
-
const CAPTURE_DECL_OFFICE = {
|
|
65
|
-
host: 'outlook.office.com',
|
|
66
|
-
path: '/*',
|
|
67
|
-
headerName: 'authorization',
|
|
68
|
-
};
|
|
69
49
|
/**
|
|
70
|
-
* The
|
|
50
|
+
* The two Outlook Web origins a signed-in tab can be on: the new one first,
|
|
51
|
+
* then the legacy one still serving tenants not yet migrated.
|
|
71
52
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
53
|
+
* Only one is ever DECLARED to the bridge (`captureHost`). Both stay listed
|
|
54
|
+
* for validating `OUTLOOK_WEB_HOST` and for a hosted registration's egress.
|
|
74
55
|
*/
|
|
75
|
-
export const
|
|
56
|
+
export const OUTLOOK_WEB_HOSTS = ['outlook.cloud.microsoft', 'outlook.office.com'];
|
|
76
57
|
/**
|
|
77
|
-
* The
|
|
58
|
+
* The ONE host to capture from and declare to the bridge: `OUTLOOK_WEB_HOST`,
|
|
59
|
+
* or `outlook.cloud.microsoft` by default.
|
|
78
60
|
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
61
|
+
* This declared both hosts until 0.8.1, and the bridge opens a background
|
|
62
|
+
* relay tab for every declared domain that has no tab open, after every hello.
|
|
63
|
+
* A signed-in `outlook.office.com` tab redirects to `outlook.cloud.microsoft`,
|
|
64
|
+
* so no tab ever matched the second domain and each capture opened another
|
|
65
|
+
* one. The second capture also ran after the first (the bridge serializes
|
|
66
|
+
* them), so a capture from the legacy host waited out the other host's window
|
|
67
|
+
* first.
|
|
83
68
|
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
69
|
+
* Declaring one host fixes both. It is also the smallest scope the bridge can
|
|
70
|
+
* be asked for, and the same on every hello, so it never offers a grant again.
|
|
71
|
+
* Changing the host changes the domain set, which the bridge re-pairs on — a
|
|
72
|
+
* one-time approval.
|
|
73
|
+
*
|
|
74
|
+
* An unrecognised value throws rather than falling back: capturing from the
|
|
75
|
+
* wrong host just times out, with nothing saying why.
|
|
88
76
|
*/
|
|
89
|
-
export
|
|
77
|
+
export function captureHost(env = process.env) {
|
|
78
|
+
const raw = readEnvVar('OUTLOOK_WEB_HOST', { env });
|
|
79
|
+
if (raw === undefined)
|
|
80
|
+
return OUTLOOK_WEB_HOSTS[0];
|
|
81
|
+
const host = raw.trim().toLowerCase();
|
|
82
|
+
const known = OUTLOOK_WEB_HOSTS.find((h) => h === host);
|
|
83
|
+
if (known === undefined) {
|
|
84
|
+
throw new Error(`OUTLOOK_WEB_HOST=${JSON.stringify(raw)} is not an Outlook Web host. Use ` +
|
|
85
|
+
`${OUTLOOK_WEB_HOSTS.join(' or ')} — whichever your signed-in Outlook tab is on — or unset it.`);
|
|
86
|
+
}
|
|
87
|
+
return known;
|
|
88
|
+
}
|
|
90
89
|
/**
|
|
91
90
|
* How long to wait for the page to make a request we can read.
|
|
92
91
|
*
|
|
@@ -96,16 +95,19 @@ export const TRUST_DOMAINS = [...CAPTURE_HOSTS];
|
|
|
96
95
|
* long enough that ordinary polling or a user glance lands inside it, short
|
|
97
96
|
* enough that an idle tab does not hang a tool call for minutes.
|
|
98
97
|
*/
|
|
99
|
-
const
|
|
98
|
+
const DEFAULT_CAPTURE_WINDOW_MS = 30_000;
|
|
100
99
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
* Build the capture transport through this module's import binding, so the
|
|
101
|
+
* test can stand in for the bridge. mcp-utils' own default calls its internal
|
|
102
|
+
* reference, which a module mock cannot reach.
|
|
103
|
+
*/
|
|
104
|
+
const createCaptureTransport = (opts) => createFetchproxyTransport(opts);
|
|
105
|
+
/**
|
|
106
|
+
* Capture an Outlook access token from the user's signed-in browser tab on
|
|
107
|
+
* `captureHost(env)`. Returns the bare token (no `Bearer ` prefix).
|
|
107
108
|
*/
|
|
108
|
-
export async function captureTokenViaFetchproxy() {
|
|
109
|
+
export async function captureTokenViaFetchproxy(env = process.env) {
|
|
110
|
+
const host = captureHost(env);
|
|
109
111
|
// `captureBearerHeader` declares only `capture_request_header` beside the
|
|
110
112
|
// `fetch` base verb, derives the bridge deadline from the window (window +
|
|
111
113
|
// 15 s, never under 30 s) so a raised window is not cut off early, starts the
|
|
@@ -114,15 +116,21 @@ export async function captureTokenViaFetchproxy() {
|
|
|
114
116
|
// header too short to be a token (real ones are ~5 KB of JWT), and closes
|
|
115
117
|
// the transport whatever happened.
|
|
116
118
|
return captureBearerHeader({
|
|
117
|
-
captures: [
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
captures: [{ host, path: '/*', headerName: 'authorization' }],
|
|
120
|
+
// Exactly the host captured from: every API call afterwards is a plain
|
|
121
|
+
// server-side `fetch` the bridge never sees. (The apex `cloud.microsoft` /
|
|
122
|
+
// `office.com` once declared here granted the whole of Microsoft 365.)
|
|
123
|
+
domains: [host],
|
|
124
|
+
// Read per capture, not at import, so the env this server was given wins.
|
|
125
|
+
windowMs: readTtlMsEnv('OUTLOOK_CAPTURE_TIMEOUT', DEFAULT_CAPTURE_WINDOW_MS, { env }),
|
|
126
|
+
port: getWsPort(env),
|
|
121
127
|
serverName: PACKAGE_NAME,
|
|
122
128
|
version: VERSION,
|
|
123
129
|
what: 'an Outlook token',
|
|
124
|
-
guidance:
|
|
125
|
-
'
|
|
126
|
-
|
|
130
|
+
guidance: `Open a signed-in Outlook tab on ${host}, leave it in the foreground for a ` +
|
|
131
|
+
'moment so the page makes a request, and retry. If your Outlook is on the ' +
|
|
132
|
+
`other host (${OUTLOOK_WEB_HOSTS.filter((h) => h !== host).join(', ')}), set ` +
|
|
133
|
+
'OUTLOOK_WEB_HOST to it.',
|
|
134
|
+
createTransport: createCaptureTransport,
|
|
127
135
|
});
|
|
128
136
|
}
|
package/dist/bundle.js
CHANGED
|
@@ -39086,7 +39086,7 @@ var init_version = __esm({
|
|
|
39086
39086
|
"src/version.ts"() {
|
|
39087
39087
|
"use strict";
|
|
39088
39088
|
PACKAGE_NAME = "office-outlook-mcp";
|
|
39089
|
-
VERSION = "0.8.
|
|
39089
|
+
VERSION = "0.8.2";
|
|
39090
39090
|
}
|
|
39091
39091
|
});
|
|
39092
39092
|
|
|
@@ -49515,29 +49515,46 @@ var init_fetchproxy = __esm({
|
|
|
49515
49515
|
// src/auth-fetchproxy.ts
|
|
49516
49516
|
var auth_fetchproxy_exports = {};
|
|
49517
49517
|
__export(auth_fetchproxy_exports, {
|
|
49518
|
-
|
|
49519
|
-
|
|
49518
|
+
OUTLOOK_WEB_HOSTS: () => OUTLOOK_WEB_HOSTS,
|
|
49519
|
+
captureHost: () => captureHost,
|
|
49520
49520
|
captureTokenViaFetchproxy: () => captureTokenViaFetchproxy,
|
|
49521
49521
|
getWsPort: () => getWsPort,
|
|
49522
|
-
raceCaptures: () => raceCaptures,
|
|
49523
49522
|
stripBearer: () => stripBearer
|
|
49524
49523
|
});
|
|
49525
|
-
function getWsPort() {
|
|
49526
|
-
return readPortEnv("OUTLOOK_WS_PORT", DEFAULT_WS_PORT);
|
|
49524
|
+
function getWsPort(env = process.env) {
|
|
49525
|
+
return readPortEnv("OUTLOOK_WS_PORT", DEFAULT_WS_PORT, { env });
|
|
49526
|
+
}
|
|
49527
|
+
function captureHost(env = process.env) {
|
|
49528
|
+
const raw = readEnvVar("OUTLOOK_WEB_HOST", { env });
|
|
49529
|
+
if (raw === void 0) return OUTLOOK_WEB_HOSTS[0];
|
|
49530
|
+
const host = raw.trim().toLowerCase();
|
|
49531
|
+
const known = OUTLOOK_WEB_HOSTS.find((h) => h === host);
|
|
49532
|
+
if (known === void 0) {
|
|
49533
|
+
throw new Error(
|
|
49534
|
+
`OUTLOOK_WEB_HOST=${JSON.stringify(raw)} is not an Outlook Web host. Use ${OUTLOOK_WEB_HOSTS.join(" or ")} \u2014 whichever your signed-in Outlook tab is on \u2014 or unset it.`
|
|
49535
|
+
);
|
|
49536
|
+
}
|
|
49537
|
+
return known;
|
|
49527
49538
|
}
|
|
49528
|
-
async function captureTokenViaFetchproxy() {
|
|
49539
|
+
async function captureTokenViaFetchproxy(env = process.env) {
|
|
49540
|
+
const host = captureHost(env);
|
|
49529
49541
|
return captureBearerHeader({
|
|
49530
|
-
captures: [
|
|
49531
|
-
|
|
49532
|
-
|
|
49533
|
-
|
|
49542
|
+
captures: [{ host, path: "/*", headerName: "authorization" }],
|
|
49543
|
+
// Exactly the host captured from: every API call afterwards is a plain
|
|
49544
|
+
// server-side `fetch` the bridge never sees. (The apex `cloud.microsoft` /
|
|
49545
|
+
// `office.com` once declared here granted the whole of Microsoft 365.)
|
|
49546
|
+
domains: [host],
|
|
49547
|
+
// Read per capture, not at import, so the env this server was given wins.
|
|
49548
|
+
windowMs: readTtlMsEnv("OUTLOOK_CAPTURE_TIMEOUT", DEFAULT_CAPTURE_WINDOW_MS, { env }),
|
|
49549
|
+
port: getWsPort(env),
|
|
49534
49550
|
serverName: PACKAGE_NAME,
|
|
49535
49551
|
version: VERSION,
|
|
49536
49552
|
what: "an Outlook token",
|
|
49537
|
-
guidance:
|
|
49553
|
+
guidance: `Open a signed-in Outlook tab on ${host}, leave it in the foreground for a moment so the page makes a request, and retry. If your Outlook is on the other host (${OUTLOOK_WEB_HOSTS.filter((h) => h !== host).join(", ")}), set OUTLOOK_WEB_HOST to it.`,
|
|
49554
|
+
createTransport: createCaptureTransport
|
|
49538
49555
|
});
|
|
49539
49556
|
}
|
|
49540
|
-
var DEFAULT_WS_PORT,
|
|
49557
|
+
var DEFAULT_WS_PORT, OUTLOOK_WEB_HOSTS, DEFAULT_CAPTURE_WINDOW_MS, createCaptureTransport;
|
|
49541
49558
|
var init_auth_fetchproxy = __esm({
|
|
49542
49559
|
"src/auth-fetchproxy.ts"() {
|
|
49543
49560
|
"use strict";
|
|
@@ -49546,19 +49563,9 @@ var init_auth_fetchproxy = __esm({
|
|
|
49546
49563
|
init_version();
|
|
49547
49564
|
init_fetchproxy();
|
|
49548
49565
|
DEFAULT_WS_PORT = 37149;
|
|
49549
|
-
|
|
49550
|
-
|
|
49551
|
-
|
|
49552
|
-
headerName: "authorization"
|
|
49553
|
-
};
|
|
49554
|
-
CAPTURE_DECL_OFFICE = {
|
|
49555
|
-
host: "outlook.office.com",
|
|
49556
|
-
path: "/*",
|
|
49557
|
-
headerName: "authorization"
|
|
49558
|
-
};
|
|
49559
|
-
CAPTURE_HOSTS = [CAPTURE_DECL_CLOUD.host, CAPTURE_DECL_OFFICE.host];
|
|
49560
|
-
TRUST_DOMAINS = [...CAPTURE_HOSTS];
|
|
49561
|
-
CAPTURE_TIMEOUT_MS = readTtlMsEnv("OUTLOOK_CAPTURE_TIMEOUT", 3e4);
|
|
49566
|
+
OUTLOOK_WEB_HOSTS = ["outlook.cloud.microsoft", "outlook.office.com"];
|
|
49567
|
+
DEFAULT_CAPTURE_WINDOW_MS = 3e4;
|
|
49568
|
+
createCaptureTransport = (opts) => createFetchproxyTransport(opts);
|
|
49562
49569
|
}
|
|
49563
49570
|
});
|
|
49564
49571
|
|
package/dist/version.js
CHANGED
package/mint.yaml
CHANGED
|
@@ -55,6 +55,12 @@ env:
|
|
|
55
55
|
fetchproxy concentrator port used for token capture. Defaults to 37149,
|
|
56
56
|
the fleet-wide shared port. Name this variable in the registration's
|
|
57
57
|
bridgePortEnv for a bridged deployment.
|
|
58
|
+
- name: OUTLOOK_WEB_HOST
|
|
59
|
+
required: false
|
|
60
|
+
help: >-
|
|
61
|
+
Which Outlook Web host the signed-in tab is on: outlook.cloud.microsoft
|
|
62
|
+
(default) or outlook.office.com for a tenant still on the legacy app.
|
|
63
|
+
Only this one host is declared to the browser bridge.
|
|
58
64
|
- name: OUTLOOK_CAPTURE_TIMEOUT
|
|
59
65
|
required: false
|
|
60
66
|
help: >-
|
|
@@ -79,10 +85,10 @@ state:
|
|
|
79
85
|
re-captures from the browser — and on a scale-to-zero machine that means
|
|
80
86
|
re-prompting the user to approve pairing, constantly.
|
|
81
87
|
egress:
|
|
82
|
-
# outlook.office.com is the only host the API client fetches.
|
|
83
|
-
#
|
|
84
|
-
# registration is not blocked on either —
|
|
85
|
-
# current tenant's tab lives.
|
|
88
|
+
# outlook.office.com is the only host the API client fetches. Both Outlook
|
|
89
|
+
# Web hosts a token can be captured from (OUTLOOK_WEB_HOST picks one) are
|
|
90
|
+
# allowed, so a hosted registration is not blocked on either —
|
|
91
|
+
# outlook.cloud.microsoft is where a current tenant's tab lives.
|
|
86
92
|
allow:
|
|
87
93
|
- outlook.cloud.microsoft
|
|
88
94
|
- outlook.office.com
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrischall/office-outlook-mcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
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>",
|
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.8.
|
|
9
|
+
"version": "0.8.2",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@chrischall/office-outlook-mcp",
|
|
14
|
-
"version": "0.8.
|
|
14
|
+
"version": "0.8.2",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|
|
@@ -41,6 +41,12 @@
|
|
|
41
41
|
"isRequired": false,
|
|
42
42
|
"format": "string"
|
|
43
43
|
},
|
|
44
|
+
{
|
|
45
|
+
"name": "OUTLOOK_WEB_HOST",
|
|
46
|
+
"description": "Which Outlook Web host your signed-in tab is on: outlook.cloud.microsoft (default) or outlook.office.com for a tenant still on the legacy app. Only this one host is declared to the browser bridge.",
|
|
47
|
+
"isRequired": false,
|
|
48
|
+
"format": "string"
|
|
49
|
+
},
|
|
44
50
|
{
|
|
45
51
|
"name": "OUTLOOK_CAPTURE_TIMEOUT",
|
|
46
52
|
"description": "Seconds to wait for the Outlook tab to make a request we can read a token from. Defaults to 30.",
|
|
@@ -13,14 +13,19 @@ token** (~25h lifetime) — every actual request is a plain server-side `curl`.
|
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
15
|
npm i -g @fetchproxy/cli # provides `fpx`
|
|
16
|
-
fpx profile add outlook --domain outlook.cloud.microsoft
|
|
17
|
-
--domain outlook.office.com
|
|
16
|
+
fpx profile add outlook --domain outlook.cloud.microsoft
|
|
18
17
|
fpx profile declare outlook \
|
|
19
18
|
--capture-header authorization@outlook.cloud.microsoft \
|
|
20
|
-
--capture-header authorization@outlook.office.com \
|
|
21
19
|
--allow-download
|
|
22
20
|
```
|
|
23
21
|
|
|
22
|
+
Declare **one** host, the one your signed-in Outlook tab is on. A tenant still
|
|
23
|
+
on the legacy app uses `outlook.office.com` in both lines and exports
|
|
24
|
+
`OUTLOOK_CAPTURE_HOST=outlook.office.com`. Don't declare both: the bridge opens a
|
|
25
|
+
background tab for every declared domain with no tab open, and because a
|
|
26
|
+
signed-in `outlook.office.com` tab redirects to `outlook.cloud.microsoft`, it
|
|
27
|
+
opens another one on every capture.
|
|
28
|
+
|
|
24
29
|
Declare **all** scopes before the first pairing — widening them later forces the
|
|
25
30
|
user to re-approve. The first `fpx` call prints a 6-digit pair code to approve in
|
|
26
31
|
the ContextMint Bridge extension popup; the grant then persists.
|