@juvantlabs/m365-graph-mcp-server 0.1.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/ARCHITECTURE.md +225 -0
- package/CHANGELOG.md +188 -0
- package/LICENSE +21 -0
- package/README.md +164 -0
- package/SECURITY.md +64 -0
- package/dist/auth/confirmation_tokens.d.ts +38 -0
- package/dist/auth/confirmation_tokens.d.ts.map +1 -0
- package/dist/auth/confirmation_tokens.js +85 -0
- package/dist/auth/confirmation_tokens.js.map +1 -0
- package/dist/auth/keyring.d.ts +20 -0
- package/dist/auth/keyring.d.ts.map +1 -0
- package/dist/auth/keyring.js +41 -0
- package/dist/auth/keyring.js.map +1 -0
- package/dist/auth/msal.d.ts +42 -0
- package/dist/auth/msal.d.ts.map +1 -0
- package/dist/auth/msal.js +96 -0
- package/dist/auth/msal.js.map +1 -0
- package/dist/auth/setup.d.ts +18 -0
- package/dist/auth/setup.d.ts.map +1 -0
- package/dist/auth/setup.js +110 -0
- package/dist/auth/setup.js.map +1 -0
- package/dist/client/graph.d.ts +30 -0
- package/dist/client/graph.d.ts.map +1 -0
- package/dist/client/graph.js +38 -0
- package/dist/client/graph.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +131 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/cancel_event.d.ts +18 -0
- package/dist/tools/cancel_event.d.ts.map +1 -0
- package/dist/tools/cancel_event.js +95 -0
- package/dist/tools/cancel_event.js.map +1 -0
- package/dist/tools/copy_file.d.ts +39 -0
- package/dist/tools/copy_file.d.ts.map +1 -0
- package/dist/tools/copy_file.js +168 -0
- package/dist/tools/copy_file.js.map +1 -0
- package/dist/tools/create_event.d.ts +29 -0
- package/dist/tools/create_event.d.ts.map +1 -0
- package/dist/tools/create_event.js +144 -0
- package/dist/tools/create_event.js.map +1 -0
- package/dist/tools/decline_event.d.ts +18 -0
- package/dist/tools/decline_event.d.ts.map +1 -0
- package/dist/tools/decline_event.js +105 -0
- package/dist/tools/decline_event.js.map +1 -0
- package/dist/tools/delete_file.d.ts +28 -0
- package/dist/tools/delete_file.d.ts.map +1 -0
- package/dist/tools/delete_file.js +103 -0
- package/dist/tools/delete_file.js.map +1 -0
- package/dist/tools/download_file.d.ts +43 -0
- package/dist/tools/download_file.d.ts.map +1 -0
- package/dist/tools/download_file.js +133 -0
- package/dist/tools/download_file.js.map +1 -0
- package/dist/tools/get_event.d.ts +27 -0
- package/dist/tools/get_event.d.ts.map +1 -0
- package/dist/tools/get_event.js +55 -0
- package/dist/tools/get_event.js.map +1 -0
- package/dist/tools/index.d.ts +13 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +61 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list_calendars.d.ts +26 -0
- package/dist/tools/list_calendars.d.ts.map +1 -0
- package/dist/tools/list_calendars.js +60 -0
- package/dist/tools/list_calendars.js.map +1 -0
- package/dist/tools/list_drives.d.ts +27 -0
- package/dist/tools/list_drives.d.ts.map +1 -0
- package/dist/tools/list_drives.js +58 -0
- package/dist/tools/list_drives.js.map +1 -0
- package/dist/tools/list_events.d.ts +51 -0
- package/dist/tools/list_events.d.ts.map +1 -0
- package/dist/tools/list_events.js +119 -0
- package/dist/tools/list_events.js.map +1 -0
- package/dist/tools/list_items.d.ts +31 -0
- package/dist/tools/list_items.d.ts.map +1 -0
- package/dist/tools/list_items.js +81 -0
- package/dist/tools/list_items.js.map +1 -0
- package/dist/tools/move_file.d.ts +18 -0
- package/dist/tools/move_file.d.ts.map +1 -0
- package/dist/tools/move_file.js +60 -0
- package/dist/tools/move_file.js.map +1 -0
- package/dist/tools/search_events.d.ts +25 -0
- package/dist/tools/search_events.d.ts.map +1 -0
- package/dist/tools/search_events.js +71 -0
- package/dist/tools/search_events.js.map +1 -0
- package/dist/tools/search_events_content.d.ts +32 -0
- package/dist/tools/search_events_content.d.ts.map +1 -0
- package/dist/tools/search_events_content.js +106 -0
- package/dist/tools/search_events_content.js.map +1 -0
- package/dist/tools/search_files.d.ts +30 -0
- package/dist/tools/search_files.d.ts.map +1 -0
- package/dist/tools/search_files.js +82 -0
- package/dist/tools/search_files.js.map +1 -0
- package/dist/tools/update_event.d.ts +25 -0
- package/dist/tools/update_event.d.ts.map +1 -0
- package/dist/tools/update_event.js +123 -0
- package/dist/tools/update_event.js.map +1 -0
- package/dist/tools/upload_file.d.ts +38 -0
- package/dist/tools/upload_file.d.ts.map +1 -0
- package/dist/tools/upload_file.js +152 -0
- package/dist/tools/upload_file.js.map +1 -0
- package/dist/types/tool.d.ts +32 -0
- package/dist/types/tool.d.ts.map +1 -0
- package/dist/types/tool.js +10 -0
- package/dist/types/tool.js.map +1 -0
- package/dist/types/validators.d.ts +44 -0
- package/dist/types/validators.d.ts.map +1 -0
- package/dist/types/validators.js +78 -0
- package/dist/types/validators.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: m365-graph:move_file
|
|
3
|
+
*
|
|
4
|
+
* Move a file or folder to a different parent folder. Wraps Graph's
|
|
5
|
+
* `PATCH /me/drive/items/{id}` with a `parentReference` body — atomic,
|
|
6
|
+
* synchronous within the same drive (no async polling required, unlike
|
|
7
|
+
* copy_file).
|
|
8
|
+
*
|
|
9
|
+
* Cross-drive moves are NOT supported via this PATCH (Microsoft
|
|
10
|
+
* recommends "copy + delete" for those). The tool refuses
|
|
11
|
+
* `target_drive_id` for now to make this restriction explicit; agents
|
|
12
|
+
* who need cross-drive should call copy_file then delete_file.
|
|
13
|
+
*
|
|
14
|
+
* Required Graph scope: `Files.ReadWrite` (delegated).
|
|
15
|
+
*/
|
|
16
|
+
import type { Tool } from "../types/tool.js";
|
|
17
|
+
export declare const moveFileTool: Tool;
|
|
18
|
+
//# sourceMappingURL=move_file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"move_file.d.ts","sourceRoot":"","sources":["../../src/tools/move_file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AASH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AAwDxF,eAAO,MAAM,YAAY,EAAE,IAA8B,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: m365-graph:move_file
|
|
3
|
+
*
|
|
4
|
+
* Move a file or folder to a different parent folder. Wraps Graph's
|
|
5
|
+
* `PATCH /me/drive/items/{id}` with a `parentReference` body — atomic,
|
|
6
|
+
* synchronous within the same drive (no async polling required, unlike
|
|
7
|
+
* copy_file).
|
|
8
|
+
*
|
|
9
|
+
* Cross-drive moves are NOT supported via this PATCH (Microsoft
|
|
10
|
+
* recommends "copy + delete" for those). The tool refuses
|
|
11
|
+
* `target_drive_id` for now to make this restriction explicit; agents
|
|
12
|
+
* who need cross-drive should call copy_file then delete_file.
|
|
13
|
+
*
|
|
14
|
+
* Required Graph scope: `Files.ReadWrite` (delegated).
|
|
15
|
+
*/
|
|
16
|
+
import { validateOptionalString, validateRequiredString, } from "../types/validators.js";
|
|
17
|
+
import { summarizeCopiedItem } from "./copy_file.js";
|
|
18
|
+
const definition = {
|
|
19
|
+
name: "m365-graph:move_file",
|
|
20
|
+
description: "Move a file or folder to a different parent folder within the same drive. Synchronous (atomic PATCH). Cross-drive moves are not supported here — use copy_file + delete_file for those.",
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {
|
|
24
|
+
item_id: { type: "string", description: "Source item ID." },
|
|
25
|
+
target_parent_id: { type: "string", description: "Destination folder ID (in the same drive)." },
|
|
26
|
+
drive_id: { type: "string", description: "Optional drive ID. Defaults to /me/drive." },
|
|
27
|
+
new_name: { type: "string", description: "Optional rename during the move." },
|
|
28
|
+
},
|
|
29
|
+
required: ["item_id", "target_parent_id"],
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
const handler = async (graph, args) => {
|
|
33
|
+
const itemId = validateRequiredString(args.item_id, "item_id");
|
|
34
|
+
const targetParentId = validateRequiredString(args.target_parent_id, "target_parent_id");
|
|
35
|
+
const driveId = validateOptionalString(args.drive_id, "drive_id");
|
|
36
|
+
const newName = validateOptionalString(args.new_name, "new_name");
|
|
37
|
+
const apiPath = driveId
|
|
38
|
+
? `/drives/${encodeURIComponent(driveId)}/items/${encodeURIComponent(itemId)}`
|
|
39
|
+
: `/me/drive/items/${encodeURIComponent(itemId)}`;
|
|
40
|
+
const body = {
|
|
41
|
+
parentReference: { id: targetParentId },
|
|
42
|
+
};
|
|
43
|
+
if (newName !== undefined)
|
|
44
|
+
body.name = newName;
|
|
45
|
+
const moved = (await graph.api(apiPath).patch(body));
|
|
46
|
+
const summary = summarizeCopiedItem(moved);
|
|
47
|
+
return {
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
type: "text",
|
|
51
|
+
text: JSON.stringify({
|
|
52
|
+
moved: summary,
|
|
53
|
+
source: { item_id: itemId, drive_id: driveId ?? null },
|
|
54
|
+
}, null, 2),
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
export const moveFileTool = { definition, handler };
|
|
60
|
+
//# sourceMappingURL=move_file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"move_file.js","sourceRoot":"","sources":["../../src/tools/move_file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAGrD,MAAM,UAAU,GAAmB;IACjC,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACT,yLAAyL;IAC3L,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE;YAC3D,gBAAgB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,4CAA4C,EAAE;YAC/F,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2CAA2C,EAAE;YACtF,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kCAAkC,EAAE;SAC9E;QACD,QAAQ,EAAE,CAAC,SAAS,EAAE,kBAAkB,CAAC;KAC1C;CACF,CAAC;AAEF,MAAM,OAAO,GAAgB,KAAK,EAChC,KAAa,EACb,IAA6B,EACN,EAAE;IACzB,MAAM,MAAM,GAAG,sBAAsB,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC/D,MAAM,cAAc,GAAG,sBAAsB,CAAC,IAAI,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;IACzF,MAAM,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAElE,MAAM,OAAO,GAAG,OAAO;QACrB,CAAC,CAAC,WAAW,kBAAkB,CAAC,OAAO,CAAC,UAAU,kBAAkB,CAAC,MAAM,CAAC,EAAE;QAC9E,CAAC,CAAC,mBAAmB,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;IAEpD,MAAM,IAAI,GAA4B;QACpC,eAAe,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE;KACxC,CAAC;IACF,IAAI,OAAO,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;IAE/C,MAAM,KAAK,GAAG,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAA4B,CAAC;IAChF,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAE3C,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;oBACE,KAAK,EAAE,OAAO;oBACd,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,IAAI,IAAI,EAAE;iBACvD,EACD,IAAI,EACJ,CAAC,CACF;aACF;SACF;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAS,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: m365-graph:search_events
|
|
3
|
+
*
|
|
4
|
+
* Search the user's events by subject. Uses Graph
|
|
5
|
+
* `/me/events?$filter=contains(subject, '…')` — subject-only because
|
|
6
|
+
* `$search` is not supported on the Events resource ("The parameter
|
|
7
|
+
* $search is not currently supported on the Events resource."). Body
|
|
8
|
+
* search would require POST /search/query (a separate Search API),
|
|
9
|
+
* deferred to a future tool.
|
|
10
|
+
*
|
|
11
|
+
* Note: $filter on events does NOT expand recurrences — series
|
|
12
|
+
* masters are returned for recurring events. For "all occurrences in
|
|
13
|
+
* a window" use list_events instead.
|
|
14
|
+
*
|
|
15
|
+
* Required Graph scope: `Calendars.Read` (delegated). Read-only.
|
|
16
|
+
*
|
|
17
|
+
* Input:
|
|
18
|
+
* query (string, required) — substring matched against event subject
|
|
19
|
+
* limit (integer 1..50) — default 20
|
|
20
|
+
*
|
|
21
|
+
* Output: same event shape as list_events.
|
|
22
|
+
*/
|
|
23
|
+
import type { Tool } from "../types/tool.js";
|
|
24
|
+
export declare const searchEventsTool: Tool;
|
|
25
|
+
//# sourceMappingURL=search_events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search_events.d.ts","sourceRoot":"","sources":["../../src/tools/search_events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AA0DxF,eAAO,MAAM,gBAAgB,EAAE,IAA8B,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: m365-graph:search_events
|
|
3
|
+
*
|
|
4
|
+
* Search the user's events by subject. Uses Graph
|
|
5
|
+
* `/me/events?$filter=contains(subject, '…')` — subject-only because
|
|
6
|
+
* `$search` is not supported on the Events resource ("The parameter
|
|
7
|
+
* $search is not currently supported on the Events resource."). Body
|
|
8
|
+
* search would require POST /search/query (a separate Search API),
|
|
9
|
+
* deferred to a future tool.
|
|
10
|
+
*
|
|
11
|
+
* Note: $filter on events does NOT expand recurrences — series
|
|
12
|
+
* masters are returned for recurring events. For "all occurrences in
|
|
13
|
+
* a window" use list_events instead.
|
|
14
|
+
*
|
|
15
|
+
* Required Graph scope: `Calendars.Read` (delegated). Read-only.
|
|
16
|
+
*
|
|
17
|
+
* Input:
|
|
18
|
+
* query (string, required) — substring matched against event subject
|
|
19
|
+
* limit (integer 1..50) — default 20
|
|
20
|
+
*
|
|
21
|
+
* Output: same event shape as list_events.
|
|
22
|
+
*/
|
|
23
|
+
import { summarizeEvent } from "./list_events.js";
|
|
24
|
+
import { validateOptionalInteger, validateRequiredString, } from "../types/validators.js";
|
|
25
|
+
const definition = {
|
|
26
|
+
name: "m365-graph:search_events",
|
|
27
|
+
description: "Search the user's events by subject (substring match). Read-only. Subject-only because Graph does not support $search on the Events resource. For 'events in a date window' use list_events instead — this tool returns recurrence series masters.",
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {
|
|
31
|
+
query: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Substring matched against the event subject (case-insensitive on the Graph side).",
|
|
34
|
+
},
|
|
35
|
+
limit: {
|
|
36
|
+
type: "integer",
|
|
37
|
+
minimum: 1,
|
|
38
|
+
maximum: 50,
|
|
39
|
+
description: "Maximum number of results to return (default 20).",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
required: ["query"],
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
const handler = async (graph, args) => {
|
|
46
|
+
const query = validateRequiredString(args.query, "query");
|
|
47
|
+
const limit = validateOptionalInteger(args.limit, "limit", {
|
|
48
|
+
min: 1,
|
|
49
|
+
max: 50,
|
|
50
|
+
default: 20,
|
|
51
|
+
});
|
|
52
|
+
// OData literal-string escape: ' → ''
|
|
53
|
+
const escapedQuery = query.replace(/'/g, "''");
|
|
54
|
+
const response = await graph
|
|
55
|
+
.api("/me/events")
|
|
56
|
+
.filter(`contains(subject, '${escapedQuery}')`)
|
|
57
|
+
.top(limit)
|
|
58
|
+
.get();
|
|
59
|
+
const items = Array.isArray(response?.value) ? response.value : [];
|
|
60
|
+
const events = items.map((e) => summarizeEvent(e));
|
|
61
|
+
const result = {
|
|
62
|
+
query,
|
|
63
|
+
count: events.length,
|
|
64
|
+
results: events,
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
export const searchEventsTool = { definition, handler };
|
|
71
|
+
//# sourceMappingURL=search_events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search_events.js","sourceRoot":"","sources":["../../src/tools/search_events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,UAAU,GAAmB;IACjC,IAAI,EAAE,0BAA0B;IAChC,WAAW,EACT,oPAAoP;IACtP,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,mFAAmF;aACjG;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,mDAAmD;aACjE;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;KACpB;CACF,CAAC;AAEF,MAAM,OAAO,GAAgB,KAAK,EAChC,KAAa,EACb,IAA6B,EACN,EAAE;IACzB,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE;QACzD,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,EAAE;QACP,OAAO,EAAE,EAAE;KACZ,CAAC,CAAC;IAEH,sCAAsC;IACtC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAE/C,MAAM,QAAQ,GAAG,MAAM,KAAK;SACzB,GAAG,CAAC,YAAY,CAAC;SACjB,MAAM,CAAC,sBAAsB,YAAY,IAAI,CAAC;SAC9C,GAAG,CAAC,KAAK,CAAC;SACV,GAAG,EAAE,CAAC;IAET,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAA0B,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5E,MAAM,MAAM,GAAG;QACb,KAAK;QACL,KAAK,EAAE,MAAM,CAAC,MAAM;QACpB,OAAO,EAAE,MAAM;KAChB,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACnE,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAS,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: m365-graph:search_events_content
|
|
3
|
+
*
|
|
4
|
+
* Body + subject content search via the Microsoft Search API
|
|
5
|
+
* (POST /search/query). Distinct from `search_events` which uses
|
|
6
|
+
* `/me/events?$filter=contains(subject, '…')` (subject-only, since
|
|
7
|
+
* Graph rejects $search on the Events resource).
|
|
8
|
+
*
|
|
9
|
+
* Trade-offs vs search_events:
|
|
10
|
+
* - Hits matched against BODY content too, not just subject.
|
|
11
|
+
* - Returns Search-API-shaped hits: `{hitId, summary, resource}`.
|
|
12
|
+
* We map back to summarizeEvent's shape using `resource` (the
|
|
13
|
+
* event payload) for consistency with the rest of the calendar
|
|
14
|
+
* surface.
|
|
15
|
+
* - Returns recurrence series masters (same as search_events) — no
|
|
16
|
+
* occurrence expansion. Use list_events for windowed occurrences.
|
|
17
|
+
*
|
|
18
|
+
* Required scope: `Calendars.Read` (delegated). The Search API
|
|
19
|
+
* inherits the user's permissions; no extra scope needed for events.
|
|
20
|
+
*
|
|
21
|
+
* Input:
|
|
22
|
+
* query (string, required) — natural-language search term
|
|
23
|
+
* limit (integer 1..50) — default 25
|
|
24
|
+
* from (integer 0..) — pagination offset (default 0)
|
|
25
|
+
*
|
|
26
|
+
* Output: `{ query, count, total, results: [<event summary>] }` where
|
|
27
|
+
* `total` is the server's reported total (may exceed `count` if
|
|
28
|
+
* paginated).
|
|
29
|
+
*/
|
|
30
|
+
import type { Tool } from "../types/tool.js";
|
|
31
|
+
export declare const searchEventsContentTool: Tool;
|
|
32
|
+
//# sourceMappingURL=search_events_content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search_events_content.d.ts","sourceRoot":"","sources":["../../src/tools/search_events_content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AASH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AA0FxF,eAAO,MAAM,uBAAuB,EAAE,IAA8B,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: m365-graph:search_events_content
|
|
3
|
+
*
|
|
4
|
+
* Body + subject content search via the Microsoft Search API
|
|
5
|
+
* (POST /search/query). Distinct from `search_events` which uses
|
|
6
|
+
* `/me/events?$filter=contains(subject, '…')` (subject-only, since
|
|
7
|
+
* Graph rejects $search on the Events resource).
|
|
8
|
+
*
|
|
9
|
+
* Trade-offs vs search_events:
|
|
10
|
+
* - Hits matched against BODY content too, not just subject.
|
|
11
|
+
* - Returns Search-API-shaped hits: `{hitId, summary, resource}`.
|
|
12
|
+
* We map back to summarizeEvent's shape using `resource` (the
|
|
13
|
+
* event payload) for consistency with the rest of the calendar
|
|
14
|
+
* surface.
|
|
15
|
+
* - Returns recurrence series masters (same as search_events) — no
|
|
16
|
+
* occurrence expansion. Use list_events for windowed occurrences.
|
|
17
|
+
*
|
|
18
|
+
* Required scope: `Calendars.Read` (delegated). The Search API
|
|
19
|
+
* inherits the user's permissions; no extra scope needed for events.
|
|
20
|
+
*
|
|
21
|
+
* Input:
|
|
22
|
+
* query (string, required) — natural-language search term
|
|
23
|
+
* limit (integer 1..50) — default 25
|
|
24
|
+
* from (integer 0..) — pagination offset (default 0)
|
|
25
|
+
*
|
|
26
|
+
* Output: `{ query, count, total, results: [<event summary>] }` where
|
|
27
|
+
* `total` is the server's reported total (may exceed `count` if
|
|
28
|
+
* paginated).
|
|
29
|
+
*/
|
|
30
|
+
import { summarizeEvent } from "./list_events.js";
|
|
31
|
+
import { validateOptionalInteger, validateRequiredString, } from "../types/validators.js";
|
|
32
|
+
const definition = {
|
|
33
|
+
name: "m365-graph:search_events_content",
|
|
34
|
+
description: "Search the user's events by subject AND body content. Uses the Microsoft Search API (POST /search/query). Distinct from search_events (subject-only via $filter). Returns recurrence series masters; for occurrences in a window use list_events.",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
query: { type: "string", description: "Search term — matches subject + body." },
|
|
39
|
+
limit: {
|
|
40
|
+
type: "integer",
|
|
41
|
+
minimum: 1,
|
|
42
|
+
maximum: 50,
|
|
43
|
+
description: "Maximum hits to return (default 25).",
|
|
44
|
+
},
|
|
45
|
+
from: {
|
|
46
|
+
type: "integer",
|
|
47
|
+
minimum: 0,
|
|
48
|
+
description: "Pagination offset (default 0).",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
required: ["query"],
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
const handler = async (graph, args) => {
|
|
55
|
+
const query = validateRequiredString(args.query, "query");
|
|
56
|
+
const limit = validateOptionalInteger(args.limit, "limit", {
|
|
57
|
+
min: 1,
|
|
58
|
+
max: 50,
|
|
59
|
+
default: 25,
|
|
60
|
+
});
|
|
61
|
+
const from = validateOptionalInteger(args.from, "from", {
|
|
62
|
+
min: 0,
|
|
63
|
+
max: 1_000_000,
|
|
64
|
+
default: 0,
|
|
65
|
+
});
|
|
66
|
+
const body = {
|
|
67
|
+
requests: [
|
|
68
|
+
{
|
|
69
|
+
entityTypes: ["event"],
|
|
70
|
+
query: { queryString: query },
|
|
71
|
+
from,
|
|
72
|
+
size: limit,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
const response = (await graph.api("/search/query").post(body));
|
|
77
|
+
// Search API response shape:
|
|
78
|
+
// { value: [ { hitsContainers: [ { hits: [ { resource: <event>, ... }, ... ], total } ] } ] }
|
|
79
|
+
const value = Array.isArray(response.value) ? response.value : [];
|
|
80
|
+
const firstResponse = (value[0] ?? {});
|
|
81
|
+
const hitsContainers = Array.isArray(firstResponse.hitsContainers)
|
|
82
|
+
? firstResponse.hitsContainers
|
|
83
|
+
: [];
|
|
84
|
+
const firstContainer = (hitsContainers[0] ?? {});
|
|
85
|
+
const hits = Array.isArray(firstContainer.hits) ? firstContainer.hits : [];
|
|
86
|
+
const total = Number(firstContainer.total ?? hits.length);
|
|
87
|
+
const events = hits
|
|
88
|
+
.map((h) => h.resource)
|
|
89
|
+
.filter((r) => typeof r === "object" && r !== null)
|
|
90
|
+
.map((r) => summarizeEvent(r));
|
|
91
|
+
return {
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
94
|
+
type: "text",
|
|
95
|
+
text: JSON.stringify({
|
|
96
|
+
query,
|
|
97
|
+
count: events.length,
|
|
98
|
+
total,
|
|
99
|
+
results: events,
|
|
100
|
+
}, null, 2),
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
export const searchEventsContentTool = { definition, handler };
|
|
106
|
+
//# sourceMappingURL=search_events_content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search_events_content.js","sourceRoot":"","sources":["../../src/tools/search_events_content.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: m365-graph:search_files
|
|
3
|
+
*
|
|
4
|
+
* Search for files by name/content within a drive (the user's primary
|
|
5
|
+
* OneDrive by default, or a specified `drive_id`). Wraps the Graph
|
|
6
|
+
* `/drives/{id}/root/search(q='…')` OData function.
|
|
7
|
+
*
|
|
8
|
+
* Required Graph scope: `Files.Read` (delegated). Read-only.
|
|
9
|
+
*
|
|
10
|
+
* Input:
|
|
11
|
+
* query (string, required) — search term
|
|
12
|
+
* drive_id (string, optional) — drive to search; default = /me/drive
|
|
13
|
+
* limit (integer, 1..50) — max items to return; default 20
|
|
14
|
+
*
|
|
15
|
+
* Output: JSON array of matching items with name, path, size, lastModified, webUrl.
|
|
16
|
+
*/
|
|
17
|
+
import type { Tool } from "../types/tool.js";
|
|
18
|
+
interface SearchHit {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
path: string;
|
|
22
|
+
size: number;
|
|
23
|
+
is_folder: boolean;
|
|
24
|
+
lastModified: string;
|
|
25
|
+
webUrl: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function summarizeSearchHit(item: Record<string, unknown>): SearchHit;
|
|
28
|
+
export declare const searchFilesTool: Tool;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=search_files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search_files.d.ts","sourceRoot":"","sources":["../../src/tools/search_files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AA6BxF,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAc3E;AAkCD,eAAO,MAAM,eAAe,EAAE,IAA8B,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: m365-graph:search_files
|
|
3
|
+
*
|
|
4
|
+
* Search for files by name/content within a drive (the user's primary
|
|
5
|
+
* OneDrive by default, or a specified `drive_id`). Wraps the Graph
|
|
6
|
+
* `/drives/{id}/root/search(q='…')` OData function.
|
|
7
|
+
*
|
|
8
|
+
* Required Graph scope: `Files.Read` (delegated). Read-only.
|
|
9
|
+
*
|
|
10
|
+
* Input:
|
|
11
|
+
* query (string, required) — search term
|
|
12
|
+
* drive_id (string, optional) — drive to search; default = /me/drive
|
|
13
|
+
* limit (integer, 1..50) — max items to return; default 20
|
|
14
|
+
*
|
|
15
|
+
* Output: JSON array of matching items with name, path, size, lastModified, webUrl.
|
|
16
|
+
*/
|
|
17
|
+
import { validateOptionalInteger, validateOptionalString, validateRequiredString, } from "../types/validators.js";
|
|
18
|
+
const definition = {
|
|
19
|
+
name: "m365-graph:search_files",
|
|
20
|
+
description: "Search for files within a drive by name and content. Defaults to the user's primary OneDrive; pass drive_id to search a specific drive (e.g. a SharePoint document library). Returns up to `limit` matching items. Read-only.",
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {
|
|
24
|
+
query: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "Search term — matches file name and content.",
|
|
27
|
+
},
|
|
28
|
+
drive_id: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "Optional drive ID to search. Defaults to the user's primary OneDrive (/me/drive).",
|
|
31
|
+
},
|
|
32
|
+
limit: {
|
|
33
|
+
type: "integer",
|
|
34
|
+
minimum: 1,
|
|
35
|
+
maximum: 50,
|
|
36
|
+
description: "Maximum number of results to return (default 20).",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
required: ["query"],
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
export function summarizeSearchHit(item) {
|
|
43
|
+
const parentRef = item.parentReference;
|
|
44
|
+
const parentPath = parentRef?.path ?? "";
|
|
45
|
+
const name = String(item.name ?? "");
|
|
46
|
+
const path = parentPath ? `${parentPath}/${name}` : name;
|
|
47
|
+
return {
|
|
48
|
+
id: String(item.id ?? ""),
|
|
49
|
+
name,
|
|
50
|
+
path,
|
|
51
|
+
size: Number(item.size ?? 0),
|
|
52
|
+
is_folder: item.folder !== undefined,
|
|
53
|
+
lastModified: String(item.lastModifiedDateTime ?? ""),
|
|
54
|
+
webUrl: String(item.webUrl ?? ""),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const handler = async (graph, args) => {
|
|
58
|
+
const query = validateRequiredString(args.query, "query");
|
|
59
|
+
const driveId = validateOptionalString(args.drive_id, "drive_id");
|
|
60
|
+
const limit = validateOptionalInteger(args.limit, "limit", {
|
|
61
|
+
min: 1,
|
|
62
|
+
max: 50,
|
|
63
|
+
default: 20,
|
|
64
|
+
});
|
|
65
|
+
const driveRoot = driveId ? `/drives/${encodeURIComponent(driveId)}` : "/me/drive";
|
|
66
|
+
const escapedQuery = query.replace(/'/g, "''");
|
|
67
|
+
const apiPath = `${driveRoot}/root/search(q='${escapedQuery}')`;
|
|
68
|
+
const response = await graph.api(apiPath).top(limit).get();
|
|
69
|
+
const items = Array.isArray(response?.value) ? response.value : [];
|
|
70
|
+
const hits = items.map((i) => summarizeSearchHit(i));
|
|
71
|
+
const result = {
|
|
72
|
+
query,
|
|
73
|
+
drive_id: driveId ?? null,
|
|
74
|
+
count: hits.length,
|
|
75
|
+
results: hits,
|
|
76
|
+
};
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
export const searchFilesTool = { definition, handler };
|
|
82
|
+
//# sourceMappingURL=search_files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search_files.js","sourceRoot":"","sources":["../../src/tools/search_files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: m365-graph:update_event
|
|
3
|
+
*
|
|
4
|
+
* Update an existing event. Wraps Graph `PATCH /me/events/{id}`.
|
|
5
|
+
*
|
|
6
|
+
* Required Graph scope: `Calendars.ReadWrite` (delegated).
|
|
7
|
+
*
|
|
8
|
+
* Important: when updating attendees, Graph REPLACES the entire list
|
|
9
|
+
* — it does not merge. To add a single attendee, fetch the event with
|
|
10
|
+
* get_event, append to the existing list, and pass the full updated
|
|
11
|
+
* list. The tool documents this in the `attendees` field description
|
|
12
|
+
* so the agent doesn't accidentally truncate the invite list.
|
|
13
|
+
*
|
|
14
|
+
* Send-update behavior: Graph automatically notifies attendees of
|
|
15
|
+
* changes that affect the meeting (time, location, attendee list).
|
|
16
|
+
* That's the desired UX for a meeting invitation flow; for cosmetic
|
|
17
|
+
* updates the user's email client may not show "updated" indicators.
|
|
18
|
+
*
|
|
19
|
+
* Returns the updated event in summarizeEvent shape.
|
|
20
|
+
*/
|
|
21
|
+
import type { Tool } from "../types/tool.js";
|
|
22
|
+
declare function buildPatchBody(args: Record<string, unknown>): Record<string, unknown>;
|
|
23
|
+
export { buildPatchBody };
|
|
24
|
+
export declare const updateEventTool: Tool;
|
|
25
|
+
//# sourceMappingURL=update_event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update_event.d.ts","sourceRoot":"","sources":["../../src/tools/update_event.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAUH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AA0CxF,iBAAS,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6D9E;AAuBD,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,eAAO,MAAM,eAAe,EAAE,IAA8B,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: m365-graph:update_event
|
|
3
|
+
*
|
|
4
|
+
* Update an existing event. Wraps Graph `PATCH /me/events/{id}`.
|
|
5
|
+
*
|
|
6
|
+
* Required Graph scope: `Calendars.ReadWrite` (delegated).
|
|
7
|
+
*
|
|
8
|
+
* Important: when updating attendees, Graph REPLACES the entire list
|
|
9
|
+
* — it does not merge. To add a single attendee, fetch the event with
|
|
10
|
+
* get_event, append to the existing list, and pass the full updated
|
|
11
|
+
* list. The tool documents this in the `attendees` field description
|
|
12
|
+
* so the agent doesn't accidentally truncate the invite list.
|
|
13
|
+
*
|
|
14
|
+
* Send-update behavior: Graph automatically notifies attendees of
|
|
15
|
+
* changes that affect the meeting (time, location, attendee list).
|
|
16
|
+
* That's the desired UX for a meeting invitation flow; for cosmetic
|
|
17
|
+
* updates the user's email client may not show "updated" indicators.
|
|
18
|
+
*
|
|
19
|
+
* Returns the updated event in summarizeEvent shape.
|
|
20
|
+
*/
|
|
21
|
+
import { summarizeEvent } from "./list_events.js";
|
|
22
|
+
import { validateOptionalEnum, validateOptionalString, validateRequiredString, } from "../types/validators.js";
|
|
23
|
+
const BODY_CONTENT_TYPES = ["text", "html"];
|
|
24
|
+
const ATTENDEE_TYPES = ["required", "optional", "resource"];
|
|
25
|
+
const definition = {
|
|
26
|
+
name: "m365-graph:update_event",
|
|
27
|
+
description: "Update an existing event (subject, time, body, location, attendees). All fields except event_id are optional — only the provided fields are PATCHed. WARNING: when updating attendees, Graph REPLACES the entire list. Pass the full intended list, not a delta. Returns the updated event.",
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {
|
|
31
|
+
event_id: { type: "string", description: "Event id from list_events / search_events." },
|
|
32
|
+
subject: { type: "string" },
|
|
33
|
+
start: { type: "string", description: "ISO 8601 datetime; if updating time, also pass `end` and optionally `timezone`." },
|
|
34
|
+
end: { type: "string" },
|
|
35
|
+
timezone: { type: "string", description: "IANA timezone (e.g. 'Europe/Rome'). Required if `start` or `end` is updated." },
|
|
36
|
+
body: { type: "string" },
|
|
37
|
+
body_content_type: { type: "string", enum: ["text", "html"], description: "Default: 'text'." },
|
|
38
|
+
location: { type: "string" },
|
|
39
|
+
attendees: {
|
|
40
|
+
type: "array",
|
|
41
|
+
description: "REPLACES the existing attendee list. Each item: {email, name?, type?}.",
|
|
42
|
+
items: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
email: { type: "string" },
|
|
46
|
+
name: { type: "string" },
|
|
47
|
+
type: { type: "string", enum: ["required", "optional", "resource"] },
|
|
48
|
+
},
|
|
49
|
+
required: ["email"],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
is_all_day: { type: "boolean" },
|
|
53
|
+
},
|
|
54
|
+
required: ["event_id"],
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
function buildPatchBody(args) {
|
|
58
|
+
const body = {};
|
|
59
|
+
const subject = validateOptionalString(args.subject, "subject");
|
|
60
|
+
if (subject !== undefined)
|
|
61
|
+
body.subject = subject;
|
|
62
|
+
const start = validateOptionalString(args.start, "start");
|
|
63
|
+
const end = validateOptionalString(args.end, "end");
|
|
64
|
+
const timezone = validateOptionalString(args.timezone, "timezone");
|
|
65
|
+
if (start !== undefined || end !== undefined) {
|
|
66
|
+
if (timezone === undefined) {
|
|
67
|
+
throw new Error("'timezone' is required when 'start' or 'end' is updated");
|
|
68
|
+
}
|
|
69
|
+
if (start !== undefined)
|
|
70
|
+
body.start = { dateTime: start, timeZone: timezone };
|
|
71
|
+
if (end !== undefined)
|
|
72
|
+
body.end = { dateTime: end, timeZone: timezone };
|
|
73
|
+
}
|
|
74
|
+
const bodyText = validateOptionalString(args.body, "body");
|
|
75
|
+
if (bodyText !== undefined) {
|
|
76
|
+
const contentType = validateOptionalEnum(args.body_content_type, "body_content_type", BODY_CONTENT_TYPES, "text");
|
|
77
|
+
body.body = { contentType, content: bodyText };
|
|
78
|
+
}
|
|
79
|
+
const location = validateOptionalString(args.location, "location");
|
|
80
|
+
if (location !== undefined)
|
|
81
|
+
body.location = { displayName: location };
|
|
82
|
+
if (args.attendees !== undefined) {
|
|
83
|
+
if (!Array.isArray(args.attendees))
|
|
84
|
+
throw new Error("'attendees' must be an array");
|
|
85
|
+
body.attendees = args.attendees.map((raw, i) => {
|
|
86
|
+
if (typeof raw !== "object" || raw === null) {
|
|
87
|
+
throw new Error(`'attendees[${i}]' must be an object`);
|
|
88
|
+
}
|
|
89
|
+
const a = raw;
|
|
90
|
+
const email = validateRequiredString(a.email, `attendees[${i}].email`);
|
|
91
|
+
const name = validateOptionalString(a.name, `attendees[${i}].name`);
|
|
92
|
+
const type = validateOptionalEnum(a.type, `attendees[${i}].type`, ATTENDEE_TYPES, "required");
|
|
93
|
+
return {
|
|
94
|
+
emailAddress: name ? { address: email, name } : { address: email },
|
|
95
|
+
type,
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (args.is_all_day !== undefined) {
|
|
100
|
+
if (typeof args.is_all_day !== "boolean") {
|
|
101
|
+
throw new Error("'is_all_day' must be boolean");
|
|
102
|
+
}
|
|
103
|
+
body.isAllDay = args.is_all_day;
|
|
104
|
+
}
|
|
105
|
+
return body;
|
|
106
|
+
}
|
|
107
|
+
const handler = async (graph, args) => {
|
|
108
|
+
const eventId = validateRequiredString(args.event_id, "event_id");
|
|
109
|
+
const patchBody = buildPatchBody(args);
|
|
110
|
+
if (Object.keys(patchBody).length === 0) {
|
|
111
|
+
throw new Error("update_event requires at least one field to update besides event_id");
|
|
112
|
+
}
|
|
113
|
+
const updated = await graph
|
|
114
|
+
.api(`/me/events/${encodeURIComponent(eventId)}`)
|
|
115
|
+
.patch(patchBody);
|
|
116
|
+
const summary = summarizeEvent(updated);
|
|
117
|
+
return {
|
|
118
|
+
content: [{ type: "text", text: JSON.stringify({ updated: summary }, null, 2) }],
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
export { buildPatchBody };
|
|
122
|
+
export const updateEventTool = { definition, handler };
|
|
123
|
+
//# sourceMappingURL=update_event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update_event.js","sourceRoot":"","sources":["../../src/tools/update_event.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAU,CAAC;AAGrD,MAAM,cAAc,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,CAAU,CAAC;AAGrE,MAAM,UAAU,GAAmB;IACjC,IAAI,EAAE,yBAAyB;IAC/B,WAAW,EACT,6RAA6R;IAC/R,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,4CAA4C,EAAE;YACvF,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iFAAiF,EAAE;YACzH,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACvB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8EAA8E,EAAE;YACzH,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACxB,iBAAiB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,kBAAkB,EAAE;YAC9F,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC5B,SAAS,EAAE;gBACT,IAAI,EAAE,OAAO;gBACb,WAAW,EAAE,wEAAwE;gBACrF,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACzB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACxB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE;qBACrE;oBACD,QAAQ,EAAE,CAAC,OAAO,CAAC;iBACpB;aACF;YACD,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;SAChC;QACD,QAAQ,EAAE,CAAC,UAAU,CAAC;KACvB;CACF,CAAC;AAEF,SAAS,cAAc,CAAC,IAA6B;IACnD,MAAM,IAAI,GAA4B,EAAE,CAAC;IAEzC,MAAM,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAChE,IAAI,OAAO,KAAK,SAAS;QAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAElD,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,sBAAsB,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,sBAAsB,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACnE,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QAC7C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;QAC9E,IAAI,GAAG,KAAK,SAAS;YAAE,IAAI,CAAC,GAAG,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAC1E,CAAC;IAED,MAAM,QAAQ,GAAG,sBAAsB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3D,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,oBAAoB,CACtC,IAAI,CAAC,iBAAiB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,MAAM,CACP,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,QAAQ,GAAG,sBAAsB,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACnE,IAAI,QAAQ,KAAK,SAAS;QAAE,IAAI,CAAC,QAAQ,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;IAEtE,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACpF,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;YAC7C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBAC5C,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;YACzD,CAAC;YACD,MAAM,CAAC,GAAG,GAA8B,CAAC;YACzC,MAAM,KAAK,GAAG,sBAAsB,CAAC,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;YACvE,MAAM,IAAI,GAAG,sBAAsB,CAAC,CAAC,CAAC,IAAI,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;YACpE,MAAM,IAAI,GAAG,oBAAoB,CAC/B,CAAC,CAAC,IAAI,EACN,aAAa,CAAC,QAAQ,EACtB,cAAc,EACd,UAAU,CACX,CAAC;YACF,OAAO;gBACL,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE;gBAClE,IAAI;aACL,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAClC,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC;IAClC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,OAAO,GAAgB,KAAK,EAChC,KAAa,EACb,IAA6B,EACN,EAAE;IACzB,MAAM,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,KAAK;SACxB,GAAG,CAAC,cAAc,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;SAChD,KAAK,CAAC,SAAS,CAAC,CAAC;IAEpB,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAExC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACjF,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,MAAM,CAAC,MAAM,eAAe,GAAS,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC"}
|