@chrischall/office-outlook-mcp 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/bundle.js +27 -13
- package/dist/copilot/session.js +4 -1
- package/dist/index.js +1 -1
- package/dist/tools/calendar.js +3 -3
- package/dist/tools/copilot.js +31 -4
- package/dist/version.js +1 -1
- package/dist/view.js +18 -1
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "MCP server for Outlook / Microsoft 365 — mail, calendar, contacts and tasks via natural language",
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.10.0"
|
|
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.
|
|
18
|
+
"version": "0.10.0",
|
|
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.
|
|
4
|
+
"version": "0.10.0",
|
|
5
5
|
"description": "Outlook / Microsoft 365 for Claude — triage unread mail, reply, answer meeting invites and schedule meetings, plus folders, calendar, contacts and tasks, with confirmation before anything is sent, using your signed-in browser session",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Chris Hall",
|
package/dist/bundle.js
CHANGED
|
@@ -39293,7 +39293,7 @@ var init_version = __esm({
|
|
|
39293
39293
|
"src/version.ts"() {
|
|
39294
39294
|
"use strict";
|
|
39295
39295
|
PACKAGE_NAME = "office-outlook-mcp";
|
|
39296
|
-
VERSION = "0.
|
|
39296
|
+
VERSION = "0.10.0";
|
|
39297
39297
|
}
|
|
39298
39298
|
});
|
|
39299
39299
|
|
|
@@ -68470,13 +68470,17 @@ function compactEvent(e) {
|
|
|
68470
68470
|
ShowAs: e.ShowAs
|
|
68471
68471
|
});
|
|
68472
68472
|
}
|
|
68473
|
+
function eventAttendees(e) {
|
|
68474
|
+
return e.Attendees?.map((a) => pruned({ Who: addr(a), Response: a.Status?.Response }));
|
|
68475
|
+
}
|
|
68476
|
+
function detailedEvent(e) {
|
|
68477
|
+
return pruned({ ...compactEvent(e), Attendees: eventAttendees(e) });
|
|
68478
|
+
}
|
|
68473
68479
|
function fullEvent(e) {
|
|
68474
68480
|
return pruned({
|
|
68475
68481
|
...compactEvent(e),
|
|
68476
68482
|
SeriesMasterId: e.SeriesMasterId,
|
|
68477
|
-
Attendees: e
|
|
68478
|
-
(a) => pruned({ Who: addr(a), Response: a.Status?.Response })
|
|
68479
|
-
),
|
|
68483
|
+
Attendees: eventAttendees(e),
|
|
68480
68484
|
// The Teams link lives under OnlineMeeting; OnlineMeetingUrl is empty on
|
|
68481
68485
|
// every live Teams meeting checked.
|
|
68482
68486
|
JoinUrl: e.OnlineMeeting?.JoinUrl || e.OnlineMeetingUrl || void 0,
|
|
@@ -69199,7 +69203,7 @@ function registerCalendarTools(server, client2) {
|
|
|
69199
69203
|
server.registerTool(
|
|
69200
69204
|
"outlook_get_event",
|
|
69201
69205
|
{
|
|
69202
|
-
description:
|
|
69206
|
+
description: 'Get one calendar event with its attendees and their responses. Attendees come back in EVERY view, including the default compact one \u2014 all of them, uncapped (no 20-address cap as on a message\'s To/Cc). The event\'s time is labelled with its zone in the `TimeZone` field (the mailbox zone unless you pass `timeZone`); the same instant read in another zone shows a different clock time, so read `TimeZone`, not just the clock. view:"full" adds the Teams join link, body preview and web link; view:"raw" returns Outlook\'s untouched record. ' + UNTRUSTED_DESCRIPTION_SUFFIX,
|
|
69203
69207
|
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
69204
69208
|
_meta: workMeta("lookup"),
|
|
69205
69209
|
inputSchema: external_exports.object({
|
|
@@ -69216,7 +69220,7 @@ function registerCalendarTools(server, client2) {
|
|
|
69216
69220
|
);
|
|
69217
69221
|
const v = resolveView(view, VIEWS2);
|
|
69218
69222
|
if (v === "raw") return mailboxUntrusted(data);
|
|
69219
|
-
return mailboxUntrusted(v === "
|
|
69223
|
+
return mailboxUntrusted(v === "full" ? fullEvent(data) : detailedEvent(data));
|
|
69220
69224
|
}
|
|
69221
69225
|
);
|
|
69222
69226
|
server.registerTool(
|
|
@@ -71631,7 +71635,7 @@ function decodeJwt(token) {
|
|
|
71631
71635
|
return { oid: claims.oid, tid: claims.tid };
|
|
71632
71636
|
}
|
|
71633
71637
|
function cleanAnswer(text) {
|
|
71634
|
-
return text.replace(/[\u{E000}-\u{F8FF}\u{F0000}-\u{FFFFD}\u{100000}-\u{10FFFD}]/gu, "").replace(/cite(?:turn\d+[a-z]+\d+)+/gi, "").replace(/【[^】]{1,60}】/g, "").replace(/[ \t]+\n/g, "\n").replace(/[ \t]{2,}/g, " ").trim();
|
|
71638
|
+
return text.replace(/[\u{E000}-\u{F8FF}\u{F0000}-\u{FFFFD}\u{100000}-\u{10FFFD}]/gu, "").replace(/cite(?:turn\d+[a-z]+\d+)+/gi, "").replace(/【[^】]{1,60}】/g, "").replace(/[ \t]+\n/g, "\n").replace(/(\S)[ \t]{2,}/g, "$1 ").trim();
|
|
71635
71639
|
}
|
|
71636
71640
|
var DisengagedError = class extends Error {
|
|
71637
71641
|
disengaged = true;
|
|
@@ -71898,6 +71902,12 @@ function abortError() {
|
|
|
71898
71902
|
}
|
|
71899
71903
|
|
|
71900
71904
|
// src/tools/copilot.ts
|
|
71905
|
+
async function timeContext(outlook) {
|
|
71906
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
71907
|
+
const zone = await mailboxTimeZone(outlook);
|
|
71908
|
+
return zone ? `(Context: today is ${today}. The user's mailbox time zone is ${zone}, and mailbox times are stored in UTC. When you state any date or time, convert it to ${zone} and label the zone.)` : `(Context: today is ${today}. Mailbox times are stored in UTC \u2014 when you state a time, label its time zone.)`;
|
|
71909
|
+
}
|
|
71910
|
+
var VERBATIM_DIRECTIVE = "(Reproduce any content I ask you to quote or return IN FULL and verbatim \u2014 do not summarise, paraphrase, shorten, or omit any part of it, even if it is long.)";
|
|
71901
71911
|
var TURN_TIMEOUT_MS = 12e4;
|
|
71902
71912
|
function turnSignal(hostSignal) {
|
|
71903
71913
|
const controller = new AbortController();
|
|
@@ -71916,23 +71926,27 @@ function turnSignal(hostSignal) {
|
|
|
71916
71926
|
}
|
|
71917
71927
|
};
|
|
71918
71928
|
}
|
|
71919
|
-
function registerCopilotTools(server, copilot2) {
|
|
71929
|
+
function registerCopilotTools(server, copilot2, outlook) {
|
|
71920
71930
|
server.registerTool(
|
|
71921
71931
|
"outlook_ask_copilot",
|
|
71922
71932
|
{
|
|
71923
|
-
description: 'Ask Microsoft 365 Copilot a question answered from the signed-in mailbox (Copilot searches your own mail, calendar and files server-side and writes a reply). Use it for synthesis across many messages \u2014 "what needs my attention first", "summarise the thread with X", "did anyone ask me for anything this week". Follow-up calls continue the same conversation; pass newConversation:true to start fresh. The prompt is sent to Microsoft\'s Copilot service on your tenant; put your own question in it, not text copied from an email. Each call uses one of a per-conversation quota, reported back. First use needs a one-time sign-in: run `opencode-m365 login` (from the opencode-m365-copilot package) so an MSAL cache exists.' + UNTRUSTED_DESCRIPTION_SUFFIX,
|
|
71933
|
+
description: 'Ask Microsoft 365 Copilot a question answered from the signed-in mailbox (Copilot searches your own mail, calendar and files server-side and writes a reply). Use it for synthesis across many messages \u2014 "what needs my attention first", "summarise the thread with X", "did anyone ask me for anything this week". Follow-up calls continue the same conversation; pass newConversation:true to start fresh. Pass verbatim:true when you need content quoted back in full (Copilot otherwise answers concisely and summarises long material; for a single item a focused "quote X in full" also works). Times are converted to the mailbox time zone and labelled. The prompt is sent to Microsoft\'s Copilot service on your tenant; put your own question in it, not text copied from an email. Each call uses one of a per-conversation quota, reported back. First use needs a one-time sign-in: run `opencode-m365 login` (from the opencode-m365-copilot package) so an MSAL cache exists.' + UNTRUSTED_DESCRIPTION_SUFFIX,
|
|
71924
71934
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
71925
71935
|
_meta: workMeta("lookup", { aliases: ["copilot", "ask copilot", "m365 copilot"] }),
|
|
71926
71936
|
inputSchema: external_exports.object({
|
|
71927
71937
|
prompt: external_exports.string().min(1).describe("The question for Copilot, in your own words"),
|
|
71928
|
-
newConversation: external_exports.boolean().optional().describe("Start a fresh conversation with no prior context (default false: continue the current one)")
|
|
71938
|
+
newConversation: external_exports.boolean().optional().describe("Start a fresh conversation with no prior context (default false: continue the current one)"),
|
|
71939
|
+
verbatim: external_exports.boolean().optional().describe("Ask Copilot to quote requested content in full rather than summarising (default false). Use for retrieving a saved note, a full message, etc.")
|
|
71929
71940
|
})
|
|
71930
71941
|
},
|
|
71931
|
-
async ({ prompt, newConversation }, ctx) => {
|
|
71942
|
+
async ({ prompt, newConversation, verbatim }, ctx) => {
|
|
71932
71943
|
if (newConversation) copilot2.reset();
|
|
71933
71944
|
const { signal, dispose } = turnSignal(ctx?.signal);
|
|
71934
71945
|
try {
|
|
71935
|
-
const
|
|
71946
|
+
const preamble = [await timeContext(outlook), verbatim ? VERBATIM_DIRECTIVE : ""].filter(Boolean).join(" ");
|
|
71947
|
+
const result = await copilot2.ask(`${preamble}
|
|
71948
|
+
|
|
71949
|
+
${prompt}`, { signal });
|
|
71936
71950
|
return mailboxUntrusted({
|
|
71937
71951
|
answer: result.text,
|
|
71938
71952
|
conversationId: copilot2.conversationId,
|
|
@@ -72090,7 +72104,7 @@ await runMcp({
|
|
|
72090
72104
|
registerWriteTools,
|
|
72091
72105
|
registerExportTools,
|
|
72092
72106
|
registerRuleTools,
|
|
72093
|
-
(server) => registerCopilotTools(server, copilot),
|
|
72107
|
+
(server) => registerCopilotTools(server, copilot, client),
|
|
72094
72108
|
registerHealthcheckTool
|
|
72095
72109
|
]
|
|
72096
72110
|
});
|
package/dist/copilot/session.js
CHANGED
|
@@ -98,7 +98,10 @@ export function cleanAnswer(text) {
|
|
|
98
98
|
.replace(/cite(?:turn\d+[a-z]+\d+)+/gi, '')
|
|
99
99
|
.replace(/【[^】]{1,60}】/g, '')
|
|
100
100
|
.replace(/[ \t]+\n/g, '\n')
|
|
101
|
-
|
|
101
|
+
// Collapse only runs that FOLLOW a non-space character (the double spaces a
|
|
102
|
+
// removed token leaves mid-line), never leading indentation — a Copilot
|
|
103
|
+
// answer can quote an indented code block from a mail or note.
|
|
104
|
+
.replace(/(\S)[ \t]{2,}/g, '$1 ')
|
|
102
105
|
.trim();
|
|
103
106
|
}
|
|
104
107
|
/** M365 refused to engage with the prompt. Not a rate limit — do not retry into it. */
|
package/dist/index.js
CHANGED
package/dist/tools/calendar.js
CHANGED
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { McpToolError, minifiedResult, resolveView, viewParam } from '@chrischall/mcp-utils';
|
|
3
3
|
import { mailboxUntrusted, UNTRUSTED_DESCRIPTION_SUFFIX } from './_untrusted.js';
|
|
4
4
|
import { briefDate, briefLine, briefResult, briefViewParam, spaced, workMeta } from './_hints.js';
|
|
5
|
-
import { compactEvent, fullEvent, projectCollection, VIEWS, } from '../view.js';
|
|
5
|
+
import { compactEvent, detailedEvent, fullEvent, projectCollection, VIEWS, } from '../view.js';
|
|
6
6
|
import { fetchPage, nextLinkParam, plainCollection } from './_paging.js';
|
|
7
7
|
import { mailboxTimeZone } from '../timezone.js';
|
|
8
8
|
const EVENT_SELECT = 'Id,Subject,Start,End,Location,Organizer,IsAllDay,IsCancelled,ShowAs,OnlineMeetingUrl,OnlineMeeting,BodyPreview,' +
|
|
@@ -89,7 +89,7 @@ export function registerCalendarTools(server, client) {
|
|
|
89
89
|
return mailboxUntrusted(projectCollection(data, v === 'full' ? fullEvent : compactEvent, 'event'));
|
|
90
90
|
});
|
|
91
91
|
server.registerTool('outlook_get_event', {
|
|
92
|
-
description: 'Get one calendar event
|
|
92
|
+
description: 'Get one calendar event with its attendees and their responses. Attendees come back in EVERY view, including the default compact one — all of them, uncapped (no 20-address cap as on a message\'s To/Cc). The event\'s time is labelled with its zone in the `TimeZone` field (the mailbox zone unless you pass `timeZone`); the same instant read in another zone shows a different clock time, so read `TimeZone`, not just the clock. view:"full" adds the Teams join link, body preview and web link; view:"raw" returns Outlook\'s untouched record.' +
|
|
93
93
|
' ' + UNTRUSTED_DESCRIPTION_SUFFIX,
|
|
94
94
|
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
95
95
|
_meta: workMeta('lookup'),
|
|
@@ -104,7 +104,7 @@ export function registerCalendarTools(server, client) {
|
|
|
104
104
|
const v = resolveView(view, VIEWS);
|
|
105
105
|
if (v === 'raw')
|
|
106
106
|
return mailboxUntrusted(data);
|
|
107
|
-
return mailboxUntrusted(v === '
|
|
107
|
+
return mailboxUntrusted(v === 'full' ? fullEvent(data) : detailedEvent(data));
|
|
108
108
|
});
|
|
109
109
|
server.registerTool('outlook_list_calendars', {
|
|
110
110
|
description: 'List the calendars in the mailbox, for picking one to read or write against.',
|
package/dist/tools/copilot.js
CHANGED
|
@@ -14,8 +14,28 @@
|
|
|
14
14
|
import { z } from 'zod';
|
|
15
15
|
import { minifiedResult } from '@chrischall/mcp-utils';
|
|
16
16
|
import { DisengagedError } from '../copilot/session.js';
|
|
17
|
+
import { mailboxTimeZone } from '../timezone.js';
|
|
17
18
|
import { workMeta } from './_hints.js';
|
|
18
19
|
import { mailboxUntrusted, UNTRUSTED_DESCRIPTION_SUFFIX } from './_untrusted.js';
|
|
20
|
+
/**
|
|
21
|
+
* A short context preamble prepended to every Copilot prompt.
|
|
22
|
+
*
|
|
23
|
+
* Copilot renders a stored UTC time as a bare clock with no zone — a 2026-11-09
|
|
24
|
+
* UTC time came back as "11:41 AM", which reads as local but is not. Telling it
|
|
25
|
+
* today's date and the mailbox zone, and to convert and label, fixes the
|
|
26
|
+
* labelling at the source. The mailbox zone is read once (cached per client); if
|
|
27
|
+
* it cannot be read — a server set up for Copilot but not the Outlook mail
|
|
28
|
+
* token — the instruction degrades to "label the zone" with no date-math hint.
|
|
29
|
+
*/
|
|
30
|
+
async function timeContext(outlook) {
|
|
31
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
32
|
+
const zone = await mailboxTimeZone(outlook);
|
|
33
|
+
return zone
|
|
34
|
+
? `(Context: today is ${today}. The user's mailbox time zone is ${zone}, and mailbox times are stored in UTC. When you state any date or time, convert it to ${zone} and label the zone.)`
|
|
35
|
+
: `(Context: today is ${today}. Mailbox times are stored in UTC — when you state a time, label its time zone.)`;
|
|
36
|
+
}
|
|
37
|
+
/** The extra instruction a verbatim request prepends. */
|
|
38
|
+
const VERBATIM_DIRECTIVE = "(Reproduce any content I ask you to quote or return IN FULL and verbatim — do not summarise, paraphrase, shorten, or omit any part of it, even if it is long.)";
|
|
19
39
|
/** Stop a turn that outlives this, so a wedged connection cannot hang the call. */
|
|
20
40
|
const TURN_TIMEOUT_MS = 120_000;
|
|
21
41
|
/**
|
|
@@ -41,9 +61,9 @@ function turnSignal(hostSignal) {
|
|
|
41
61
|
},
|
|
42
62
|
};
|
|
43
63
|
}
|
|
44
|
-
export function registerCopilotTools(server, copilot) {
|
|
64
|
+
export function registerCopilotTools(server, copilot, outlook) {
|
|
45
65
|
server.registerTool('outlook_ask_copilot', {
|
|
46
|
-
description: 'Ask Microsoft 365 Copilot a question answered from the signed-in mailbox (Copilot searches your own mail, calendar and files server-side and writes a reply). Use it for synthesis across many messages — "what needs my attention first", "summarise the thread with X", "did anyone ask me for anything this week". Follow-up calls continue the same conversation; pass newConversation:true to start fresh. The prompt is sent to Microsoft\'s Copilot service on your tenant; put your own question in it, not text copied from an email. Each call uses one of a per-conversation quota, reported back. First use needs a one-time sign-in: run `opencode-m365 login` (from the opencode-m365-copilot package) so an MSAL cache exists.' +
|
|
66
|
+
description: 'Ask Microsoft 365 Copilot a question answered from the signed-in mailbox (Copilot searches your own mail, calendar and files server-side and writes a reply). Use it for synthesis across many messages — "what needs my attention first", "summarise the thread with X", "did anyone ask me for anything this week". Follow-up calls continue the same conversation; pass newConversation:true to start fresh. Pass verbatim:true when you need content quoted back in full (Copilot otherwise answers concisely and summarises long material; for a single item a focused "quote X in full" also works). Times are converted to the mailbox time zone and labelled. The prompt is sent to Microsoft\'s Copilot service on your tenant; put your own question in it, not text copied from an email. Each call uses one of a per-conversation quota, reported back. First use needs a one-time sign-in: run `opencode-m365 login` (from the opencode-m365-copilot package) so an MSAL cache exists.' +
|
|
47
67
|
UNTRUSTED_DESCRIPTION_SUFFIX,
|
|
48
68
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
49
69
|
_meta: workMeta('lookup', { aliases: ['copilot', 'ask copilot', 'm365 copilot'] }),
|
|
@@ -53,13 +73,20 @@ export function registerCopilotTools(server, copilot) {
|
|
|
53
73
|
.boolean()
|
|
54
74
|
.optional()
|
|
55
75
|
.describe('Start a fresh conversation with no prior context (default false: continue the current one)'),
|
|
76
|
+
verbatim: z
|
|
77
|
+
.boolean()
|
|
78
|
+
.optional()
|
|
79
|
+
.describe('Ask Copilot to quote requested content in full rather than summarising (default false). Use for retrieving a saved note, a full message, etc.'),
|
|
56
80
|
}),
|
|
57
|
-
}, async ({ prompt, newConversation }, ctx) => {
|
|
81
|
+
}, async ({ prompt, newConversation, verbatim }, ctx) => {
|
|
58
82
|
if (newConversation)
|
|
59
83
|
copilot.reset();
|
|
60
84
|
const { signal, dispose } = turnSignal(ctx?.signal);
|
|
61
85
|
try {
|
|
62
|
-
const
|
|
86
|
+
const preamble = [await timeContext(outlook), verbatim ? VERBATIM_DIRECTIVE : '']
|
|
87
|
+
.filter(Boolean)
|
|
88
|
+
.join(' ');
|
|
89
|
+
const result = await copilot.ask(`${preamble}\n\n${prompt}`, { signal });
|
|
63
90
|
return mailboxUntrusted({
|
|
64
91
|
answer: result.text,
|
|
65
92
|
conversationId: copilot.conversationId,
|
package/dist/version.js
CHANGED
package/dist/view.js
CHANGED
|
@@ -100,11 +100,28 @@ export function compactEvent(e) {
|
|
|
100
100
|
ShowAs: e.ShowAs,
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
|
+
/** Attendees projected as `{ Who, Response }`, or undefined when there are none. */
|
|
104
|
+
export function eventAttendees(e) {
|
|
105
|
+
return e.Attendees?.map((a) => pruned({ Who: addr(a), Response: a.Status?.Response }));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A single event's compact view WITH its attendees — what outlook_get_event
|
|
109
|
+
* returns by default.
|
|
110
|
+
*
|
|
111
|
+
* A single event is not a list, so the per-item cap that keeps attendees off
|
|
112
|
+
* list_events (one `calendarview` page can hold dozens of events) does not
|
|
113
|
+
* apply, and the attendees are the point of looking one event up. list_events
|
|
114
|
+
* still uses the attendee-free {@link compactEvent}; only get_event carries them
|
|
115
|
+
* in its compact view, as its description promises.
|
|
116
|
+
*/
|
|
117
|
+
export function detailedEvent(e) {
|
|
118
|
+
return pruned({ ...compactEvent(e), Attendees: eventAttendees(e) });
|
|
119
|
+
}
|
|
103
120
|
export function fullEvent(e) {
|
|
104
121
|
return pruned({
|
|
105
122
|
...compactEvent(e),
|
|
106
123
|
SeriesMasterId: e.SeriesMasterId,
|
|
107
|
-
Attendees: e
|
|
124
|
+
Attendees: eventAttendees(e),
|
|
108
125
|
// The Teams link lives under OnlineMeeting; OnlineMeetingUrl is empty on
|
|
109
126
|
// every live Teams meeting checked.
|
|
110
127
|
JoinUrl: e.OnlineMeeting?.JoinUrl || e.OnlineMeetingUrl || undefined,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrischall/office-outlook-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
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.
|
|
9
|
+
"version": "0.10.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@chrischall/office-outlook-mcp",
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.10.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|