@sam2kb/m365-mcp 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +4 -0
- package/README.md +21 -6
- package/SKILL.md +10 -2
- package/dist/auth-cli.js +1 -1
- package/dist/auth-cli.js.map +1 -1
- package/dist/auth.js +73 -17
- package/dist/auth.js.map +1 -1
- package/dist/graph.d.ts +3 -1
- package/dist/graph.js +88 -26
- package/dist/graph.js.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/security.js +2 -2
- package/dist/security.js.map +1 -1
- package/dist/tools/calendar.d.ts +7 -0
- package/dist/tools/calendar.js +57 -42
- package/dist/tools/calendar.js.map +1 -1
- package/dist/tools/contacts.js +1 -8
- package/dist/tools/contacts.js.map +1 -1
- package/dist/tools/files.d.ts +6 -0
- package/dist/tools/files.js +6 -5
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/mail.d.ts +4 -0
- package/dist/tools/mail.js +12 -6
- package/dist/tools/mail.js.map +1 -1
- package/dist/tools/tasks.d.ts +2 -0
- package/dist/tools/tasks.js +6 -3
- package/dist/tools/tasks.js.map +1 -1
- package/dist/tools/teams.d.ts +4 -0
- package/dist/tools/teams.js +8 -7
- package/dist/tools/teams.js.map +1 -1
- package/dist/tools/users.d.ts +2 -0
- package/dist/tools/users.js +6 -3
- package/dist/tools/users.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/validation.d.ts +7 -0
- package/dist/validation.js +26 -0
- package/dist/validation.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +4 -0
- package/dist/version.js.map +1 -0
- package/package.json +3 -3
package/dist/graph.js
CHANGED
|
@@ -9,12 +9,17 @@ import { getAccessToken } from "./auth.js";
|
|
|
9
9
|
const GRAPH_BASE = "https://graph.microsoft.com/v1.0";
|
|
10
10
|
const MAX_RETRIES = 4;
|
|
11
11
|
const RETRY_BACKOFF_MS = 1000;
|
|
12
|
+
const REQUEST_TIMEOUT_MS = 30_000;
|
|
13
|
+
const MAX_DOWNLOAD_BYTES = 1_000_000;
|
|
14
|
+
const TRANSIENT_STATUSES = new Set([500, 502, 503, 504]);
|
|
12
15
|
function retryDelayMs(retryAfter, fallbackMs) {
|
|
13
|
-
if (!retryAfter)
|
|
16
|
+
if (!retryAfter?.trim())
|
|
14
17
|
return fallbackMs;
|
|
15
18
|
const seconds = Number(retryAfter);
|
|
16
19
|
if (Number.isFinite(seconds) && seconds >= 0)
|
|
17
20
|
return seconds * 1000;
|
|
21
|
+
if (/^-?\d+(\.\d+)?$/.test(retryAfter.trim()))
|
|
22
|
+
return fallbackMs;
|
|
18
23
|
const retryAt = Date.parse(retryAfter);
|
|
19
24
|
return Number.isNaN(retryAt) ? fallbackMs : Math.max(0, retryAt - Date.now());
|
|
20
25
|
}
|
|
@@ -26,8 +31,7 @@ export class GraphClient {
|
|
|
26
31
|
this.timezone = timezone;
|
|
27
32
|
}
|
|
28
33
|
// ─── request ────────────────────────────────────────────────────
|
|
29
|
-
async request(path, method = "GET", body, raw = false, additionalHeaders = {}) {
|
|
30
|
-
const token = await getAccessToken(this.accountName);
|
|
34
|
+
async request(path, method = "GET", body, raw = false, additionalHeaders = {}, retrySafe = method === "GET") {
|
|
31
35
|
const url = path.startsWith("https://") ? path : `${GRAPH_BASE}${path}`;
|
|
32
36
|
if (new URL(url).origin !== new URL(GRAPH_BASE).origin) {
|
|
33
37
|
throw new Error("Graph API request URL must use graph.microsoft.com");
|
|
@@ -35,17 +39,21 @@ export class GraphClient {
|
|
|
35
39
|
let attempt = 0;
|
|
36
40
|
let delay = RETRY_BACKOFF_MS;
|
|
37
41
|
while (true) {
|
|
42
|
+
const headers = new Headers({
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
Accept: "application/json",
|
|
45
|
+
Prefer: `outlook.timezone="${this.timezone}"`,
|
|
46
|
+
});
|
|
47
|
+
for (const [key, value] of Object.entries(additionalHeaders))
|
|
48
|
+
headers.set(key, value);
|
|
49
|
+
// Headers is case-insensitive, so callers cannot override the selected token.
|
|
50
|
+
headers.set("Authorization", `Bearer ${await getAccessToken(this.accountName)}`);
|
|
38
51
|
const opts = {
|
|
39
52
|
method,
|
|
40
|
-
headers
|
|
41
|
-
|
|
42
|
-
Authorization: `Bearer ${token}`,
|
|
43
|
-
"Content-Type": "application/json",
|
|
44
|
-
Accept: "application/json",
|
|
45
|
-
Prefer: `outlook.timezone="${this.timezone}"`,
|
|
46
|
-
},
|
|
53
|
+
headers,
|
|
54
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
47
55
|
};
|
|
48
|
-
if (body && method !== "GET") {
|
|
56
|
+
if (body !== undefined && method !== "GET") {
|
|
49
57
|
opts.body = JSON.stringify(body);
|
|
50
58
|
}
|
|
51
59
|
let resp;
|
|
@@ -53,6 +61,9 @@ export class GraphClient {
|
|
|
53
61
|
resp = await fetch(url, opts);
|
|
54
62
|
}
|
|
55
63
|
catch (error) {
|
|
64
|
+
if (!retrySafe) {
|
|
65
|
+
throw new Error("Graph write outcome is unknown after a connection failure. Check the target before retrying.", { cause: error });
|
|
66
|
+
}
|
|
56
67
|
if (attempt >= MAX_RETRIES)
|
|
57
68
|
throw error;
|
|
58
69
|
await new Promise((r) => setTimeout(r, delay));
|
|
@@ -70,17 +81,20 @@ export class GraphClient {
|
|
|
70
81
|
}
|
|
71
82
|
const retryAfter = resp.headers.get("Retry-After");
|
|
72
83
|
const waitMs = retryDelayMs(retryAfter, delay);
|
|
84
|
+
await resp.body?.cancel();
|
|
73
85
|
await new Promise((r) => setTimeout(r, waitMs));
|
|
74
86
|
attempt++;
|
|
75
87
|
delay *= 2;
|
|
76
88
|
continue;
|
|
77
89
|
}
|
|
78
90
|
// Transient server error — retry
|
|
79
|
-
if (resp.status
|
|
91
|
+
if (TRANSIENT_STATUSES.has(resp.status) && retrySafe) {
|
|
80
92
|
if (attempt >= MAX_RETRIES) {
|
|
81
93
|
throw new Error(`Graph API server error ${resp.status} after ${MAX_RETRIES} retries`);
|
|
82
94
|
}
|
|
83
|
-
|
|
95
|
+
const waitMs = retryDelayMs(resp.headers.get("Retry-After"), delay);
|
|
96
|
+
await resp.body?.cancel();
|
|
97
|
+
await new Promise((r) => setTimeout(r, waitMs));
|
|
84
98
|
attempt++;
|
|
85
99
|
delay *= 2;
|
|
86
100
|
continue;
|
|
@@ -96,13 +110,13 @@ export class GraphClient {
|
|
|
96
110
|
catch {
|
|
97
111
|
// Graph action endpoints such as sendMail commonly return 202 with
|
|
98
112
|
// an empty body. A successful empty response is not an error.
|
|
99
|
-
if (resp.
|
|
113
|
+
if (resp.status === 202)
|
|
100
114
|
return undefined;
|
|
101
115
|
throw new Error(`Graph API ${resp.status}: unable to parse response`);
|
|
102
116
|
}
|
|
103
117
|
if (!resp.ok) {
|
|
104
118
|
const err = parsed?.error;
|
|
105
|
-
throw new Error(`Graph API ${resp.status}: ${err?.message ?? resp.statusText}`);
|
|
119
|
+
throw new Error(`Graph API ${resp.status}${err?.code ? ` [${err.code}]` : ""}: ${err?.message ?? resp.statusText}${!retrySafe && resp.status >= 500 ? ". Write outcome may be unknown; check the target before retrying." : ""}`);
|
|
106
120
|
}
|
|
107
121
|
return parsed;
|
|
108
122
|
}
|
|
@@ -114,6 +128,10 @@ export class GraphClient {
|
|
|
114
128
|
}
|
|
115
129
|
/** GET that follows @odata.nextLink pagination, collecting all results */
|
|
116
130
|
async getAll(path, maxPages = 10, maxItems = Infinity, additionalHeaders = {}) {
|
|
131
|
+
if (!Number.isInteger(maxPages) || maxPages < 1)
|
|
132
|
+
throw new Error("maxPages must be a positive integer");
|
|
133
|
+
if (maxItems !== Infinity && (!Number.isInteger(maxItems) || maxItems < 0))
|
|
134
|
+
throw new Error("maxItems must be a nonnegative integer");
|
|
117
135
|
const results = [];
|
|
118
136
|
let url = path;
|
|
119
137
|
let pages = 0;
|
|
@@ -140,8 +158,8 @@ export class GraphClient {
|
|
|
140
158
|
}
|
|
141
159
|
}
|
|
142
160
|
/** POST */
|
|
143
|
-
async post(path, body) {
|
|
144
|
-
return this.request(path, "POST", body);
|
|
161
|
+
async post(path, body, options = {}) {
|
|
162
|
+
return this.request(path, "POST", body, false, {}, options.retrySafe ?? false);
|
|
145
163
|
}
|
|
146
164
|
/** PATCH */
|
|
147
165
|
async patch(path, body) {
|
|
@@ -153,10 +171,15 @@ export class GraphClient {
|
|
|
153
171
|
}
|
|
154
172
|
/** Download raw file content with retry on transient failures */
|
|
155
173
|
async download(url, maxBytes = 50_000) {
|
|
174
|
+
if (!Number.isInteger(maxBytes) || maxBytes < 0 || maxBytes > MAX_DOWNLOAD_BYTES) {
|
|
175
|
+
throw new Error(`maxBytes must be an integer between 0 and ${MAX_DOWNLOAD_BYTES}`);
|
|
176
|
+
}
|
|
156
177
|
const downloadUrl = new URL(url);
|
|
157
178
|
if (downloadUrl.protocol !== "https:") {
|
|
158
179
|
throw new Error("Download URL must use HTTPS");
|
|
159
180
|
}
|
|
181
|
+
if (maxBytes === 0)
|
|
182
|
+
return "";
|
|
160
183
|
// Graph may return a pre-authenticated SharePoint/OneDrive download URL.
|
|
161
184
|
// Never forward the Microsoft Graph bearer token to another origin.
|
|
162
185
|
const headers = {};
|
|
@@ -167,18 +190,30 @@ export class GraphClient {
|
|
|
167
190
|
let attempt = 0;
|
|
168
191
|
let delay = RETRY_BACKOFF_MS;
|
|
169
192
|
while (true) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
193
|
+
let resp;
|
|
194
|
+
try {
|
|
195
|
+
resp = await fetch(url, { headers, signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
if (attempt >= MAX_RETRIES)
|
|
199
|
+
throw error;
|
|
200
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
201
|
+
attempt++;
|
|
202
|
+
delay *= 2;
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
173
205
|
if (resp.status === 429 && attempt < MAX_RETRIES) {
|
|
174
206
|
const retryAfter = resp.headers.get("Retry-After");
|
|
207
|
+
await resp.body?.cancel();
|
|
175
208
|
await new Promise((r) => setTimeout(r, retryDelayMs(retryAfter, delay)));
|
|
176
209
|
attempt++;
|
|
177
210
|
delay *= 2;
|
|
178
211
|
continue;
|
|
179
212
|
}
|
|
180
|
-
if (
|
|
181
|
-
|
|
213
|
+
if (TRANSIENT_STATUSES.has(resp.status) && attempt < MAX_RETRIES) {
|
|
214
|
+
const waitMs = retryDelayMs(resp.headers.get("Retry-After"), delay);
|
|
215
|
+
await resp.body?.cancel();
|
|
216
|
+
await new Promise((r) => setTimeout(r, waitMs));
|
|
182
217
|
attempt++;
|
|
183
218
|
delay *= 2;
|
|
184
219
|
continue;
|
|
@@ -186,14 +221,41 @@ export class GraphClient {
|
|
|
186
221
|
if (!resp.ok) {
|
|
187
222
|
throw new Error(`Download failed: ${resp.status} ${resp.statusText}`);
|
|
188
223
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
224
|
+
if (!resp.body)
|
|
225
|
+
return "";
|
|
226
|
+
const reader = resp.body.getReader();
|
|
227
|
+
const bytes = new Uint8Array(maxBytes);
|
|
228
|
+
let length = 0;
|
|
229
|
+
try {
|
|
230
|
+
while (length < maxBytes) {
|
|
231
|
+
const { value, done } = await reader.read();
|
|
232
|
+
if (done)
|
|
233
|
+
break;
|
|
234
|
+
const take = Math.min(value.byteLength, maxBytes - length);
|
|
235
|
+
bytes.set(value.subarray(0, take), length);
|
|
236
|
+
length += take;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
// Cancellation closes the connection even if the server ignores Range.
|
|
241
|
+
try {
|
|
242
|
+
await reader.cancel();
|
|
243
|
+
}
|
|
244
|
+
catch { /* Preserve a read failure. */ }
|
|
245
|
+
reader.releaseLock();
|
|
246
|
+
}
|
|
247
|
+
return new TextDecoder().decode(bytes.subarray(0, length));
|
|
193
248
|
}
|
|
194
249
|
}
|
|
195
250
|
/** Format a dateTimeTimeZone object for Graph API */
|
|
196
251
|
dateTimeStr(iso) {
|
|
252
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,7})?)?(?:Z|[+-]\d{2}:\d{2})?$/i.test(iso) || !Number.isFinite(Date.parse(iso))) {
|
|
253
|
+
throw new Error("Expected an ISO 8601 date-time");
|
|
254
|
+
}
|
|
255
|
+
// An explicit offset is an instant; do not reinterpret it in the configured zone.
|
|
256
|
+
if (/(?:Z|[+-]\d{2}:\d{2})$/i.test(iso)) {
|
|
257
|
+
return { dateTime: new Date(iso).toISOString().replace(/Z$/, ""), timeZone: "UTC" };
|
|
258
|
+
}
|
|
197
259
|
return { dateTime: iso, timeZone: this.timezone };
|
|
198
260
|
}
|
|
199
261
|
}
|
package/dist/graph.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,UAAU,GAAG,kCAAkC,CAAC;AACtD,MAAM,WAAW,GAAG,CAAC,CAAC;AACtB,MAAM,gBAAgB,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
10
10
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
11
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
12
12
|
import { GraphClient } from "./graph.js";
|
|
13
|
+
import { createArgumentValidator } from "./validation.js";
|
|
14
|
+
import { VERSION } from "./version.js";
|
|
13
15
|
import { registerMailTools, mailToolSchemas } from "./tools/mail.js";
|
|
14
16
|
import { registerCalendarTools, calendarToolSchemas } from "./tools/calendar.js";
|
|
15
17
|
import { registerContactsTools, contactsToolSchemas } from "./tools/contacts.js";
|
|
@@ -41,9 +43,11 @@ const allTools = toolsForMode(annotateTools([
|
|
|
41
43
|
...tasksToolSchemas,
|
|
42
44
|
...usersToolSchemas,
|
|
43
45
|
]), READ_ONLY);
|
|
46
|
+
const validateArguments = createArgumentValidator(allTools);
|
|
44
47
|
// ─── Tool router ─────────────────────────────────────────────────────
|
|
45
48
|
async function handleToolCall(name, args) {
|
|
46
49
|
assertToolAllowed(name, READ_ONLY);
|
|
50
|
+
validateArguments(name, args);
|
|
47
51
|
// Mail
|
|
48
52
|
if (name === "m365_mail_list")
|
|
49
53
|
return mailTools.mail_list(args);
|
|
@@ -146,7 +150,7 @@ async function handleToolCall(name, args) {
|
|
|
146
150
|
throw new Error(`Unknown tool: ${name}`);
|
|
147
151
|
}
|
|
148
152
|
// ─── MCP Server ──────────────────────────────────────────────────────
|
|
149
|
-
const server = new Server({ name: "m365-mcp", version:
|
|
153
|
+
const server = new Server({ name: "m365-mcp", version: VERSION }, { capabilities: { tools: {} } });
|
|
150
154
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
151
155
|
tools: allTools,
|
|
152
156
|
}));
|
|
@@ -165,7 +169,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
165
169
|
async function main() {
|
|
166
170
|
const transport = new StdioServerTransport();
|
|
167
171
|
await server.connect(transport);
|
|
168
|
-
console.error(`m365-mcp
|
|
172
|
+
console.error(`m365-mcp v${VERSION} running (account: ${ACCOUNT_NAME ?? "default"}, tz: ${TIMEZONE}, read-only: ${READ_ONLY})`);
|
|
169
173
|
}
|
|
170
|
-
main().catch(console.error);
|
|
174
|
+
main().catch((error) => { console.error(error); process.exitCode = 1; });
|
|
171
175
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,OAAO,EACP,YAAY,GACb,MAAM,eAAe,CAAC;AAEvB,wEAAwE;AAExE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,SAAS,CAAC;AAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,KAAK,CAAC;AACpD,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAE1D,wEAAwE;AAExE,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;AAEvD,MAAM,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC5C,MAAM,aAAa,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;AACpD,MAAM,aAAa,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;AACpD,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAC9C,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAC9C,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAC9C,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAE9C,wEAAwE;AAExE,MAAM,QAAQ,GAAG,YAAY,CAAC,aAAa,CAAC;IAC1C,GAAG,eAAe;IAClB,GAAG,mBAAmB;IACtB,GAAG,mBAAmB;IACtB,GAAG,gBAAgB;IACnB,GAAG,gBAAgB;IACnB,GAAG,gBAAgB;IACnB,GAAG,gBAAgB;CACpB,CAAC,EAAE,SAAS,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/security.js
CHANGED
|
@@ -68,8 +68,8 @@ const DESTRUCTIVE_TOOLS = new Set([
|
|
|
68
68
|
]);
|
|
69
69
|
const IDEMPOTENT_TOOLS = new Set([
|
|
70
70
|
"m365_mail_mark_read",
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
// Calendar updates can send notifications; delete is an organizer-cancel alias.
|
|
72
|
+
// Both remain classified as mutating and destructive above.
|
|
73
73
|
"m365_contacts_update",
|
|
74
74
|
"m365_contacts_delete",
|
|
75
75
|
"m365_contacts_folder_update",
|
package/dist/security.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,gBAAgB;IAChB,gBAAgB;IAChB,kBAAkB;IAClB,mBAAmB;IACnB,oBAAoB;IACpB,qBAAqB;IACrB,oBAAoB;IACpB,4BAA4B;IAC5B,oBAAoB;IACpB,sBAAsB;IACtB,oBAAoB;IACpB,+BAA+B;IAC/B,4BAA4B;IAC5B,2BAA2B;IAC3B,iBAAiB;IACjB,mBAAmB;IACnB,iBAAiB;IACjB,iBAAiB;IACjB,kBAAkB;IAClB,qBAAqB;IACrB,kBAAkB;IAClB,iBAAiB;IACjB,iBAAiB;IACjB,oBAAoB;IACpB,oBAAoB;CACrB,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,gBAAgB;IAChB,iBAAiB;IACjB,gBAAgB;IAChB,kBAAkB;IAClB,qBAAqB;IACrB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,uBAAuB;IACvB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,6BAA6B;IAC7B,6BAA6B;IAC7B,6BAA6B;IAC7B,0BAA0B;IAC1B,iBAAiB;IACjB,mBAAmB;IACnB,mBAAmB;IACnB,mBAAmB;CACpB,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,gBAAgB;IAChB,kBAAkB;IAClB,qBAAqB;IACrB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,uBAAuB;IACvB,sBAAsB;IACtB,sBAAsB;IACtB,6BAA6B;IAC7B,6BAA6B;IAC7B,mBAAmB;IACnB,mBAAmB;CACpB,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,qBAAqB;IACrB,
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/calendar.d.ts
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
* Calendar tools — list, today, week, create, update, cancel, decline, availability
|
|
3
3
|
*/
|
|
4
4
|
import type { GraphClient } from "../graph.js";
|
|
5
|
+
/** Build ISO 8601 start/end strings for a day in the given timezone. */
|
|
6
|
+
export declare function tzDayBounds(timezone: string, offsetDays?: number): {
|
|
7
|
+
startDateTime: string;
|
|
8
|
+
endDateTime: string;
|
|
9
|
+
};
|
|
5
10
|
export declare function registerCalendarTools(client: GraphClient): {
|
|
6
11
|
calendar_list(args: {
|
|
7
12
|
startDateTime?: string;
|
|
@@ -62,6 +67,8 @@ export declare const calendarToolSchemas: ({
|
|
|
62
67
|
};
|
|
63
68
|
top: {
|
|
64
69
|
type: string;
|
|
70
|
+
minimum: number;
|
|
71
|
+
maximum: number;
|
|
65
72
|
description: string;
|
|
66
73
|
default: number;
|
|
67
74
|
};
|
package/dist/tools/calendar.js
CHANGED
|
@@ -1,31 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Calendar tools — list, today, week, create, update, cancel, decline, availability
|
|
3
3
|
*/
|
|
4
|
+
import { normalizeTop } from "../validation.js";
|
|
4
5
|
/** Build ISO 8601 start/end strings for a day in the given timezone. */
|
|
5
|
-
function tzDayBounds(timezone, offsetDays = 0) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
6
|
+
export function tzDayBounds(timezone, offsetDays = 0) {
|
|
7
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
8
|
+
timeZone: timezone, year: "numeric", month: "2-digit", day: "2-digit",
|
|
9
|
+
}).formatToParts(new Date());
|
|
10
|
+
const part = (type) => Number(parts.find((value) => value.type === type).value);
|
|
11
|
+
const date = Date.UTC(part("year"), part("month") - 1, part("day") + offsetDays);
|
|
12
|
+
const offsetFormatter = new Intl.DateTimeFormat("en-US", { timeZone: timezone, timeZoneName: "longOffset" });
|
|
13
|
+
const midnight = (localDate) => {
|
|
14
|
+
let instant = localDate;
|
|
15
|
+
let previous = instant;
|
|
16
|
+
for (let attempt = 0; attempt < 4; attempt++) {
|
|
17
|
+
const zone = offsetFormatter.formatToParts(new Date(instant)).find((value) => value.type === "timeZoneName").value;
|
|
18
|
+
const match = zone.match(/GMT([+-])(\d{2}):(\d{2})/);
|
|
19
|
+
const offset = match ? (Number(match[2]) * 60 + Number(match[3])) * 60_000 * (match[1] === "+" ? 1 : -1) : 0;
|
|
20
|
+
const next = localDate - offset;
|
|
21
|
+
if (next === instant)
|
|
22
|
+
return instant;
|
|
23
|
+
previous = instant;
|
|
24
|
+
instant = next;
|
|
25
|
+
}
|
|
26
|
+
// If midnight is skipped by a zone transition, choose the first later instant.
|
|
27
|
+
return Math.max(previous, instant);
|
|
28
|
+
};
|
|
24
29
|
return {
|
|
25
|
-
startDateTime:
|
|
26
|
-
endDateTime:
|
|
30
|
+
startDateTime: new Date(midnight(date)).toISOString(),
|
|
31
|
+
endDateTime: new Date(midnight(date + 86400000) - 1).toISOString(),
|
|
27
32
|
};
|
|
28
33
|
}
|
|
34
|
+
// Today/week explicitly request UTC, then render in the configured timezone.
|
|
35
|
+
function utcEventDate(value) {
|
|
36
|
+
return new Date(/(?:Z|[+-]\d{2}:\d{2})$/i.test(value) ? value : `${value}Z`);
|
|
37
|
+
}
|
|
29
38
|
export function registerCalendarTools(client) {
|
|
30
39
|
const user = "/me";
|
|
31
40
|
async function cancelOrganizerEvent(args) {
|
|
@@ -38,13 +47,15 @@ export function registerCalendarTools(client) {
|
|
|
38
47
|
return {
|
|
39
48
|
// ── list ─────────────────────────────────────────────────────
|
|
40
49
|
async calendar_list(args) {
|
|
41
|
-
const top = args.top
|
|
50
|
+
const top = normalizeTop(args.top, 50);
|
|
51
|
+
if (!!args.startDateTime !== !!args.endDateTime)
|
|
52
|
+
throw new Error("Provide both startDateTime and endDateTime");
|
|
42
53
|
let path;
|
|
43
54
|
if (args.startDateTime && args.endDateTime) {
|
|
44
|
-
path = `${user}/calendarView?startDateTime=${encodeURIComponent(args.startDateTime)}&endDateTime=${encodeURIComponent(args.endDateTime)}&$top=${top}&$orderby=start/dateTime&$select=id,subject,start,end,location,isOnlineMeeting,onlineMeetingUrl,organizer,attendees,isAllDay,isOrganizer,responseStatus,webLink`;
|
|
55
|
+
path = `${user}/calendarView?startDateTime=${encodeURIComponent(args.startDateTime)}&endDateTime=${encodeURIComponent(args.endDateTime)}&$top=${top}&$orderby=start/dateTime&$select=id,subject,start,end,location,isOnlineMeeting,onlineMeeting,onlineMeetingUrl,organizer,attendees,isAllDay,isOrganizer,responseStatus,webLink`;
|
|
45
56
|
}
|
|
46
57
|
else {
|
|
47
|
-
path = `${user}/events?$top=${top}&$orderby=start/dateTime&$select=id,subject,start,end,location,isOnlineMeeting,onlineMeetingUrl,organizer,attendees,isAllDay,isOrganizer,responseStatus,webLink`;
|
|
58
|
+
path = `${user}/events?$top=${top}&$orderby=start/dateTime&$select=id,subject,start,end,location,isOnlineMeeting,onlineMeeting,onlineMeetingUrl,organizer,attendees,isAllDay,isOrganizer,responseStatus,webLink`;
|
|
48
59
|
}
|
|
49
60
|
const events = await client.getAll(path, 10, top);
|
|
50
61
|
return JSON.stringify(events.map((e) => ({
|
|
@@ -55,7 +66,7 @@ export function registerCalendarTools(client) {
|
|
|
55
66
|
isAllDay: e.isAllDay,
|
|
56
67
|
location: e.location?.displayName,
|
|
57
68
|
isOnline: e.isOnlineMeeting,
|
|
58
|
-
meetingUrl: e.onlineMeetingUrl,
|
|
69
|
+
meetingUrl: e.onlineMeeting?.joinUrl ?? e.onlineMeetingUrl,
|
|
59
70
|
organizer: e.organizer?.emailAddress?.name ?? e.organizer?.emailAddress?.address,
|
|
60
71
|
attendees: e.attendees?.length ?? 0,
|
|
61
72
|
isOrganizer: e.isOrganizer,
|
|
@@ -67,16 +78,16 @@ export function registerCalendarTools(client) {
|
|
|
67
78
|
async calendar_today() {
|
|
68
79
|
const bounds = tzDayBounds(client.timezone);
|
|
69
80
|
const path = `${user}/calendarView?startDateTime=${encodeURIComponent(bounds.startDateTime)}&endDateTime=${encodeURIComponent(bounds.endDateTime)}&$top=50&$orderby=start/dateTime`;
|
|
70
|
-
const events = await client.getAll(path, 10, 50);
|
|
81
|
+
const events = await client.getAll(path, 10, 50, { Prefer: 'outlook.timezone="UTC"' });
|
|
71
82
|
if (events.length === 0)
|
|
72
83
|
return "No events today.";
|
|
73
84
|
const now = new Date();
|
|
74
85
|
const lines = events.map((e) => {
|
|
75
|
-
const startTime =
|
|
76
|
-
const endTime =
|
|
86
|
+
const startTime = utcEventDate(e.start.dateTime);
|
|
87
|
+
const endTime = utcEventDate(e.end.dateTime);
|
|
77
88
|
const time = e.isAllDay
|
|
78
89
|
? "All Day"
|
|
79
|
-
: `${startTime.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" })}–${endTime.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" })}`;
|
|
90
|
+
: `${startTime.toLocaleTimeString("en-US", { timeZone: client.timezone, hour: "numeric", minute: "2-digit" })}–${endTime.toLocaleTimeString("en-US", { timeZone: client.timezone, hour: "numeric", minute: "2-digit" })}`;
|
|
80
91
|
let line = `${time} ${e.subject}`;
|
|
81
92
|
if (e.location?.displayName)
|
|
82
93
|
line += ` 📍 ${e.location.displayName}`;
|
|
@@ -84,21 +95,21 @@ export function registerCalendarTools(client) {
|
|
|
84
95
|
line += ` 🎥`;
|
|
85
96
|
return line;
|
|
86
97
|
});
|
|
87
|
-
return `Today (${now.toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric" })})\n${lines.join("\n")}\n\n${events.length} event${events.length !== 1 ? "s" : ""}`;
|
|
98
|
+
return `Today (${now.toLocaleDateString("en-US", { timeZone: client.timezone, weekday: "long", month: "long", day: "numeric" })})\n${lines.join("\n")}\n\n${events.length} event${events.length !== 1 ? "s" : ""}`;
|
|
88
99
|
},
|
|
89
100
|
// ── week ─────────────────────────────────────────────────────
|
|
90
101
|
async calendar_week() {
|
|
91
102
|
const startBounds = tzDayBounds(client.timezone, 0);
|
|
92
103
|
const endBounds = tzDayBounds(client.timezone, 6);
|
|
93
104
|
const path = `${user}/calendarView?startDateTime=${encodeURIComponent(startBounds.startDateTime)}&endDateTime=${encodeURIComponent(endBounds.endDateTime)}&$top=100&$orderby=start/dateTime`;
|
|
94
|
-
const events = await client.getAll(path, 10, 100);
|
|
105
|
+
const events = await client.getAll(path, 10, 100, { Prefer: 'outlook.timezone="UTC"' });
|
|
95
106
|
if (events.length === 0)
|
|
96
107
|
return "No events this week.";
|
|
97
108
|
const byDay = new Map();
|
|
98
109
|
for (const e of events) {
|
|
99
|
-
const d =
|
|
100
|
-
const key = d.toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" });
|
|
101
|
-
const startTime = d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" });
|
|
110
|
+
const d = utcEventDate(e.start.dateTime);
|
|
111
|
+
const key = d.toLocaleDateString("en-US", { timeZone: client.timezone, weekday: "short", month: "short", day: "numeric" });
|
|
112
|
+
const startTime = d.toLocaleTimeString("en-US", { timeZone: client.timezone, hour: "numeric", minute: "2-digit" });
|
|
102
113
|
let line = ` ${e.isAllDay ? "All Day" : startTime} ${e.subject}`;
|
|
103
114
|
if (e.location?.displayName)
|
|
104
115
|
line += ` 📍 ${e.location.displayName}`;
|
|
@@ -131,29 +142,33 @@ export function registerCalendarTools(client) {
|
|
|
131
142
|
type: "required",
|
|
132
143
|
}));
|
|
133
144
|
}
|
|
134
|
-
if (args.isOnline)
|
|
145
|
+
if (args.isOnline) {
|
|
135
146
|
event.isOnlineMeeting = true;
|
|
147
|
+
event.onlineMeetingProvider = "teamsForBusiness";
|
|
148
|
+
}
|
|
136
149
|
const data = await client.post(`${user}/events`, event);
|
|
137
150
|
return JSON.stringify({
|
|
138
151
|
id: data.id,
|
|
139
152
|
subject: data.subject,
|
|
140
153
|
webLink: data.webLink,
|
|
141
|
-
onlineMeetingUrl: data.onlineMeetingUrl,
|
|
154
|
+
onlineMeetingUrl: data.onlineMeeting?.joinUrl ?? data.onlineMeetingUrl,
|
|
142
155
|
}, null, 2);
|
|
143
156
|
},
|
|
144
157
|
// ── update ───────────────────────────────────────────────────
|
|
145
158
|
async calendar_update(args) {
|
|
146
159
|
const patch = {};
|
|
147
|
-
if (args.subject)
|
|
160
|
+
if (args.subject !== undefined)
|
|
148
161
|
patch.subject = args.subject;
|
|
149
162
|
if (args.start)
|
|
150
163
|
patch.start = client.dateTimeStr(args.start);
|
|
151
164
|
if (args.end)
|
|
152
165
|
patch.end = client.dateTimeStr(args.end);
|
|
153
|
-
if (args.body)
|
|
166
|
+
if (args.body !== undefined)
|
|
154
167
|
patch.body = { contentType: "HTML", content: args.body };
|
|
155
|
-
if (args.location)
|
|
168
|
+
if (args.location !== undefined)
|
|
156
169
|
patch.location = { displayName: args.location };
|
|
170
|
+
if (Object.keys(patch).length === 0)
|
|
171
|
+
throw new Error("Provide at least one event field to update");
|
|
157
172
|
const eventId = encodeURIComponent(args.eventId);
|
|
158
173
|
await client.patch(`${user}/events/${eventId}`, patch);
|
|
159
174
|
return JSON.stringify({ success: true, eventId: args.eventId });
|
|
@@ -183,7 +198,7 @@ export function registerCalendarTools(client) {
|
|
|
183
198
|
startTime: client.dateTimeStr(args.startDateTime),
|
|
184
199
|
endTime: client.dateTimeStr(args.endDateTime),
|
|
185
200
|
availabilityViewInterval: 30,
|
|
186
|
-
});
|
|
201
|
+
}, { retrySafe: true });
|
|
187
202
|
return JSON.stringify(data.value, null, 2);
|
|
188
203
|
},
|
|
189
204
|
};
|
|
@@ -191,13 +206,13 @@ export function registerCalendarTools(client) {
|
|
|
191
206
|
export const calendarToolSchemas = [
|
|
192
207
|
{
|
|
193
208
|
name: "m365_calendar_list",
|
|
194
|
-
description: "List calendar events
|
|
209
|
+
description: "List calendar events; supply both dates to expand recurring events within a range",
|
|
195
210
|
inputSchema: {
|
|
196
211
|
type: "object",
|
|
197
212
|
properties: {
|
|
198
213
|
startDateTime: { type: "string", description: "Start datetime (ISO 8601)" },
|
|
199
214
|
endDateTime: { type: "string", description: "End datetime (ISO 8601)" },
|
|
200
|
-
top: { type: "
|
|
215
|
+
top: { type: "integer", minimum: 1, maximum: 500, description: "Max events", default: 50 },
|
|
201
216
|
},
|
|
202
217
|
},
|
|
203
218
|
},
|