@goforgeit/mcp-microsoft-365 0.4.11

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.
@@ -0,0 +1,30 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+
3
+ /**
4
+ * @goforgeit/mcp-microsoft-365 — MCP server for Microsoft 365
5
+ *
6
+ * Provides Outlook, Calendar, and OneDrive tools via stdio transport.
7
+ * Uses Microsoft Graph REST API directly (no SDK dependency).
8
+ */
9
+
10
+ interface Microsoft365MCPOptions {
11
+ tokenPath: string;
12
+ clientId: string;
13
+ clientSecret: string;
14
+ }
15
+ interface ToolHandler {
16
+ handler: (args: any) => Promise<{
17
+ content: Array<{
18
+ type: 'text';
19
+ text: string;
20
+ }>;
21
+ }>;
22
+ }
23
+ interface Microsoft365MCPServer {
24
+ server: McpServer;
25
+ getRegisteredTools(): Record<string, ToolHandler>;
26
+ start(): Promise<void>;
27
+ }
28
+ declare function createMicrosoft365MCPServer(options: Microsoft365MCPOptions): Microsoft365MCPServer;
29
+
30
+ export { type Microsoft365MCPOptions, createMicrosoft365MCPServer };
package/dist/index.js ADDED
@@ -0,0 +1,409 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { z as z2 } from "zod";
7
+
8
+ // ../shared/dist/mcp-auth/forge-token-manager.js
9
+ import * as fs from "fs/promises";
10
+ import * as path from "path";
11
+ import { z } from "zod";
12
+ var ForgeOAuthTokensSchema = z.object({
13
+ accessToken: z.string(),
14
+ refreshToken: z.string().optional(),
15
+ expiresAt: z.number(),
16
+ providerId: z.string(),
17
+ connectedAt: z.string(),
18
+ scope: z.string().optional(),
19
+ email: z.string().optional(),
20
+ accountId: z.string().optional()
21
+ });
22
+ var DEFAULT_REFRESH_BUFFER_MS = 5 * 60 * 1e3;
23
+ function createForgeTokenManager(options) {
24
+ const { tokenPath, clientId, clientSecret, tokenUrl, refreshBufferMs = DEFAULT_REFRESH_BUFFER_MS } = options;
25
+ let cachedTokens = null;
26
+ const refreshCallbacks = [];
27
+ function isExpiredOrNearExpiry(tokens) {
28
+ return Date.now() >= tokens.expiresAt - refreshBufferMs;
29
+ }
30
+ async function readTokenFile() {
31
+ let raw;
32
+ try {
33
+ raw = await fs.readFile(tokenPath, "utf-8");
34
+ } catch (err) {
35
+ if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
36
+ throw new Error(`Token file not found: ${tokenPath}`);
37
+ }
38
+ throw err;
39
+ }
40
+ let parsed;
41
+ try {
42
+ parsed = JSON.parse(raw);
43
+ } catch {
44
+ throw new Error(`Invalid JSON in token file: ${tokenPath}`);
45
+ }
46
+ const result = ForgeOAuthTokensSchema.safeParse(parsed);
47
+ if (!result.success) {
48
+ throw new Error(`Invalid token file format: ${result.error.message}`);
49
+ }
50
+ return result.data;
51
+ }
52
+ async function refreshToken(tokens) {
53
+ if (!tokens.refreshToken) {
54
+ throw new Error("No refresh token available \u2014 cannot refresh expired token");
55
+ }
56
+ const body = new URLSearchParams({
57
+ grant_type: "refresh_token",
58
+ refresh_token: tokens.refreshToken,
59
+ client_id: clientId,
60
+ client_secret: clientSecret
61
+ });
62
+ const response = await fetch(tokenUrl, {
63
+ method: "POST",
64
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
65
+ body: body.toString()
66
+ });
67
+ if (!response.ok) {
68
+ const errorText = await response.text();
69
+ throw new Error(`Token refresh failed (${response.status}): ${errorText}`);
70
+ }
71
+ const data = await response.json();
72
+ const refreshedTokens = {
73
+ ...tokens,
74
+ accessToken: data.access_token,
75
+ refreshToken: data.refresh_token || tokens.refreshToken,
76
+ expiresAt: Date.now() + data.expires_in * 1e3
77
+ };
78
+ await fs.mkdir(path.dirname(tokenPath), { recursive: true });
79
+ await fs.writeFile(tokenPath, JSON.stringify(refreshedTokens), { mode: 384 });
80
+ for (const cb of refreshCallbacks) {
81
+ cb(refreshedTokens);
82
+ }
83
+ return refreshedTokens;
84
+ }
85
+ return {
86
+ async getAccessToken() {
87
+ if (cachedTokens && !isExpiredOrNearExpiry(cachedTokens)) {
88
+ return cachedTokens.accessToken;
89
+ }
90
+ const tokens = cachedTokens || await readTokenFile();
91
+ if (isExpiredOrNearExpiry(tokens)) {
92
+ if (tokens.refreshToken) {
93
+ cachedTokens = await refreshToken(tokens);
94
+ } else {
95
+ cachedTokens = tokens;
96
+ }
97
+ } else {
98
+ cachedTokens = tokens;
99
+ }
100
+ return cachedTokens.accessToken;
101
+ },
102
+ getTokenInfo() {
103
+ return cachedTokens;
104
+ },
105
+ onRefresh(callback) {
106
+ refreshCallbacks.push(callback);
107
+ }
108
+ };
109
+ }
110
+
111
+ // src/index.ts
112
+ var MS_TOKEN_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
113
+ var GRAPH_BASE = "https://graph.microsoft.com/v1.0";
114
+ function createMicrosoft365MCPServer(options) {
115
+ const tokenManager = createForgeTokenManager({
116
+ tokenPath: options.tokenPath,
117
+ clientId: options.clientId,
118
+ clientSecret: options.clientSecret,
119
+ tokenUrl: MS_TOKEN_URL
120
+ });
121
+ const server = new McpServer({
122
+ name: "@goforgeit/mcp-microsoft-365",
123
+ version: "0.1.0"
124
+ });
125
+ const registeredTools = {};
126
+ function registerTool(name, description, schema, handler) {
127
+ registeredTools[name] = { handler };
128
+ server.tool(name, description, schema, handler);
129
+ }
130
+ async function graphRequest(path2, method = "GET", body) {
131
+ const token = await tokenManager.getAccessToken();
132
+ const options2 = {
133
+ method,
134
+ headers: {
135
+ Authorization: `Bearer ${token}`,
136
+ "Content-Type": "application/json"
137
+ }
138
+ };
139
+ if (body) options2.body = JSON.stringify(body);
140
+ const response = await fetch(`${GRAPH_BASE}${path2}`, options2);
141
+ if (!response.ok) {
142
+ const errorText = await response.text();
143
+ throw new Error(`Microsoft Graph API error (${response.status}): ${errorText}`);
144
+ }
145
+ if (response.status === 204) return {};
146
+ return response.json();
147
+ }
148
+ registerTool(
149
+ "search_emails",
150
+ "Search Outlook emails",
151
+ {
152
+ query: z2.string().describe("Search query (OData $search syntax)"),
153
+ top: z2.number().optional().default(10).describe("Maximum results")
154
+ },
155
+ async (args) => {
156
+ const top = args.top || 10;
157
+ const data = await graphRequest(
158
+ `/me/messages?$search="${encodeURIComponent(args.query)}"&$top=${top}&$select=id,subject,from,receivedDateTime,bodyPreview,isRead`
159
+ );
160
+ return {
161
+ content: [
162
+ {
163
+ type: "text",
164
+ text: JSON.stringify({ messages: data.value })
165
+ }
166
+ ]
167
+ };
168
+ }
169
+ );
170
+ registerTool(
171
+ "get_email",
172
+ "Get full email details by message ID",
173
+ {
174
+ messageId: z2.string().describe("Outlook message ID")
175
+ },
176
+ async (args) => {
177
+ const data = await graphRequest(`/me/messages/${args.messageId}`);
178
+ return {
179
+ content: [{ type: "text", text: JSON.stringify(data) }]
180
+ };
181
+ }
182
+ );
183
+ registerTool("list_folders", "List Outlook mail folders", {}, async () => {
184
+ const data = await graphRequest("/me/mailFolders?$top=50");
185
+ return {
186
+ content: [
187
+ {
188
+ type: "text",
189
+ text: JSON.stringify({ folders: data.value })
190
+ }
191
+ ]
192
+ };
193
+ });
194
+ registerTool(
195
+ "create_draft",
196
+ "Create an Outlook draft email",
197
+ {
198
+ to: z2.string().describe("Recipient email address"),
199
+ subject: z2.string().describe("Email subject"),
200
+ body: z2.string().describe("Email body (plain text)")
201
+ },
202
+ async (args) => {
203
+ const data = await graphRequest("/me/messages", "POST", {
204
+ subject: args.subject,
205
+ body: { contentType: "Text", content: args.body },
206
+ toRecipients: [{ emailAddress: { address: args.to } }]
207
+ });
208
+ return {
209
+ content: [{ type: "text", text: JSON.stringify(data) }]
210
+ };
211
+ }
212
+ );
213
+ registerTool(
214
+ "archive_email",
215
+ "Move an Outlook email to Archive folder",
216
+ {
217
+ messageId: z2.string().describe("Outlook message ID to archive")
218
+ },
219
+ async (args) => {
220
+ const data = await graphRequest(`/me/messages/${args.messageId}/move`, "POST", {
221
+ destinationId: "archive"
222
+ });
223
+ return {
224
+ content: [{ type: "text", text: JSON.stringify(data) }]
225
+ };
226
+ }
227
+ );
228
+ registerTool(
229
+ "list_events",
230
+ "List calendar events in a date range",
231
+ {
232
+ startDateTime: z2.string().optional().describe("Start of range (ISO 8601)"),
233
+ endDateTime: z2.string().optional().describe("End of range (ISO 8601)"),
234
+ top: z2.number().optional().default(25).describe("Maximum events")
235
+ },
236
+ async (args) => {
237
+ let path2 = "/me/events?$orderby=start/dateTime";
238
+ path2 += `&$top=${args.top || 25}`;
239
+ if (args.startDateTime) {
240
+ path2 += `&$filter=start/dateTime ge '${args.startDateTime}'`;
241
+ if (args.endDateTime) {
242
+ path2 += ` and end/dateTime le '${args.endDateTime}'`;
243
+ }
244
+ }
245
+ path2 += "&$select=id,subject,start,end,location,attendees,bodyPreview,webLink,isAllDay,organizer";
246
+ const data = await graphRequest(path2);
247
+ return {
248
+ content: [
249
+ {
250
+ type: "text",
251
+ text: JSON.stringify({ events: data.value })
252
+ }
253
+ ]
254
+ };
255
+ }
256
+ );
257
+ registerTool(
258
+ "get_event",
259
+ "Get a specific calendar event by ID",
260
+ {
261
+ eventId: z2.string().describe("Calendar event ID")
262
+ },
263
+ async (args) => {
264
+ const data = await graphRequest(`/me/events/${args.eventId}`);
265
+ return {
266
+ content: [{ type: "text", text: JSON.stringify(data) }]
267
+ };
268
+ }
269
+ );
270
+ registerTool(
271
+ "create_event",
272
+ "Create a new calendar event in Outlook",
273
+ {
274
+ subject: z2.string().describe("Event title"),
275
+ startDateTime: z2.string().describe("Start time (ISO 8601)"),
276
+ endDateTime: z2.string().describe("End time (ISO 8601)"),
277
+ body: z2.string().optional().describe("Event description"),
278
+ location: z2.string().optional().describe("Event location"),
279
+ attendeeEmails: z2.array(z2.string()).optional().describe("Attendee email addresses")
280
+ },
281
+ async (args) => {
282
+ const event = {
283
+ subject: args.subject,
284
+ start: { dateTime: args.startDateTime, timeZone: "UTC" },
285
+ end: { dateTime: args.endDateTime, timeZone: "UTC" }
286
+ };
287
+ if (args.body) event.body = { contentType: "Text", content: args.body };
288
+ if (args.location) event.location = { displayName: args.location };
289
+ if (args.attendeeEmails) {
290
+ event.attendees = args.attendeeEmails.map((email) => ({
291
+ emailAddress: { address: email },
292
+ type: "required"
293
+ }));
294
+ }
295
+ const data = await graphRequest("/me/events", "POST", event);
296
+ return {
297
+ content: [{ type: "text", text: JSON.stringify(data) }]
298
+ };
299
+ }
300
+ );
301
+ registerTool(
302
+ "update_event",
303
+ "Update an existing Outlook calendar event",
304
+ {
305
+ eventId: z2.string().describe("Calendar event ID"),
306
+ subject: z2.string().optional().describe("New event title"),
307
+ startDateTime: z2.string().optional().describe("New start time (ISO 8601)"),
308
+ endDateTime: z2.string().optional().describe("New end time (ISO 8601)"),
309
+ body: z2.string().optional().describe("New event description"),
310
+ location: z2.string().optional().describe("New event location")
311
+ },
312
+ async (args) => {
313
+ const patch = {};
314
+ if (args.subject) patch.subject = args.subject;
315
+ if (args.body) patch.body = { contentType: "Text", content: args.body };
316
+ if (args.location) patch.location = { displayName: args.location };
317
+ if (args.startDateTime) patch.start = { dateTime: args.startDateTime, timeZone: "UTC" };
318
+ if (args.endDateTime) patch.end = { dateTime: args.endDateTime, timeZone: "UTC" };
319
+ const data = await graphRequest(`/me/events/${args.eventId}`, "PATCH", patch);
320
+ return {
321
+ content: [{ type: "text", text: JSON.stringify(data) }]
322
+ };
323
+ }
324
+ );
325
+ registerTool(
326
+ "delete_event",
327
+ "Delete an Outlook calendar event",
328
+ {
329
+ eventId: z2.string().describe("Calendar event ID to delete")
330
+ },
331
+ async (args) => {
332
+ await graphRequest(`/me/events/${args.eventId}`, "DELETE");
333
+ return {
334
+ content: [
335
+ {
336
+ type: "text",
337
+ text: JSON.stringify({ deleted: true, eventId: args.eventId })
338
+ }
339
+ ]
340
+ };
341
+ }
342
+ );
343
+ registerTool(
344
+ "search_files",
345
+ "Search OneDrive files",
346
+ {
347
+ query: z2.string().describe("Search query"),
348
+ top: z2.number().optional().default(20).describe("Maximum results")
349
+ },
350
+ async (args) => {
351
+ const top = args.top || 20;
352
+ const data = await graphRequest(
353
+ `/me/drive/root/search(q='${encodeURIComponent(args.query)}')?$top=${top}&$select=id,name,file,size,lastModifiedDateTime,webUrl`
354
+ );
355
+ return {
356
+ content: [
357
+ {
358
+ type: "text",
359
+ text: JSON.stringify({ files: data.value })
360
+ }
361
+ ]
362
+ };
363
+ }
364
+ );
365
+ registerTool(
366
+ "get_file_content",
367
+ "Get OneDrive file metadata by item ID",
368
+ {
369
+ itemId: z2.string().describe("OneDrive item ID")
370
+ },
371
+ async (args) => {
372
+ const data = await graphRequest(`/me/drive/items/${args.itemId}`);
373
+ return {
374
+ content: [{ type: "text", text: JSON.stringify(data) }]
375
+ };
376
+ }
377
+ );
378
+ return {
379
+ server,
380
+ getRegisteredTools() {
381
+ return registeredTools;
382
+ },
383
+ async start() {
384
+ const transport = new StdioServerTransport();
385
+ await server.connect(transport);
386
+ }
387
+ };
388
+ }
389
+ var isMainModule = process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/\\/g, "/"));
390
+ if (isMainModule || process.env.FORGE_MCP_START === "true") {
391
+ const tokenPath = process.env.FORGE_TOKEN_PATH;
392
+ const clientId = process.env.FORGE_CLIENT_ID;
393
+ const clientSecret = process.env.FORGE_CLIENT_SECRET;
394
+ if (!tokenPath || !clientId || !clientSecret) {
395
+ console.error(
396
+ "Required environment variables: FORGE_TOKEN_PATH, FORGE_CLIENT_ID, FORGE_CLIENT_SECRET"
397
+ );
398
+ process.exit(1);
399
+ }
400
+ const mcpServer = createMicrosoft365MCPServer({ tokenPath, clientId, clientSecret });
401
+ mcpServer.start().catch((err) => {
402
+ console.error("Failed to start MCP server:", err);
403
+ process.exit(1);
404
+ });
405
+ }
406
+ export {
407
+ createMicrosoft365MCPServer
408
+ };
409
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../../shared/src/mcp-auth/forge-token-manager.ts"],"sourcesContent":["/**\n * @goforgeit/mcp-microsoft-365 — MCP server for Microsoft 365\n *\n * Provides Outlook, Calendar, and OneDrive tools via stdio transport.\n * Uses Microsoft Graph REST API directly (no SDK dependency).\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport { createForgeTokenManager } from '@forge/shared/mcp-auth';\n\nconst MS_TOKEN_URL = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';\nconst GRAPH_BASE = 'https://graph.microsoft.com/v1.0';\n\nexport interface Microsoft365MCPOptions {\n tokenPath: string;\n clientId: string;\n clientSecret: string;\n}\n\ninterface ToolHandler {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n handler: (args: any) => Promise<{ content: Array<{ type: 'text'; text: string }> }>;\n}\n\ninterface Microsoft365MCPServer {\n server: McpServer;\n getRegisteredTools(): Record<string, ToolHandler>;\n start(): Promise<void>;\n}\n\nexport function createMicrosoft365MCPServer(\n options: Microsoft365MCPOptions,\n): Microsoft365MCPServer {\n const tokenManager = createForgeTokenManager({\n tokenPath: options.tokenPath,\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n tokenUrl: MS_TOKEN_URL,\n });\n\n const server = new McpServer({\n name: '@goforgeit/mcp-microsoft-365',\n version: '0.1.0',\n });\n\n const registeredTools: Record<string, ToolHandler> = {};\n\n function registerTool(\n name: string,\n description: string,\n schema: Record<string, z.ZodType>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n handler: (args: any) => Promise<{ content: Array<{ type: 'text'; text: string }> }>,\n ) {\n registeredTools[name] = { handler };\n server.tool(name, description, schema, handler);\n }\n\n async function graphRequest(\n path: string,\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE' = 'GET',\n body?: unknown,\n ): Promise<unknown> {\n const token = await tokenManager.getAccessToken();\n const options: RequestInit = {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n };\n if (body) options.body = JSON.stringify(body);\n\n const response = await fetch(`${GRAPH_BASE}${path}`, options);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Microsoft Graph API error (${response.status}): ${errorText}`);\n }\n\n if (response.status === 204) return {};\n return response.json();\n }\n\n // --- Outlook Tools ---\n\n registerTool(\n 'search_emails',\n 'Search Outlook emails',\n {\n query: z.string().describe('Search query (OData $search syntax)'),\n top: z.number().optional().default(10).describe('Maximum results'),\n },\n async (args: { query: string; top?: number }) => {\n const top = args.top || 10;\n const data = (await graphRequest(\n `/me/messages?$search=\"${encodeURIComponent(args.query)}\"&$top=${top}&$select=id,subject,from,receivedDateTime,bodyPreview,isRead`,\n )) as { value: unknown[] };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ messages: data.value }),\n },\n ],\n };\n },\n );\n\n registerTool(\n 'get_email',\n 'Get full email details by message ID',\n {\n messageId: z.string().describe('Outlook message ID'),\n },\n async (args: { messageId: string }) => {\n const data = await graphRequest(`/me/messages/${args.messageId}`);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(data) }],\n };\n },\n );\n\n registerTool('list_folders', 'List Outlook mail folders', {}, async () => {\n const data = (await graphRequest('/me/mailFolders?$top=50')) as { value: unknown[] };\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ folders: data.value }),\n },\n ],\n };\n });\n\n // --- Outlook Write Tools ---\n\n registerTool(\n 'create_draft',\n 'Create an Outlook draft email',\n {\n to: z.string().describe('Recipient email address'),\n subject: z.string().describe('Email subject'),\n body: z.string().describe('Email body (plain text)'),\n },\n async (args: { to: string; subject: string; body: string }) => {\n const data = await graphRequest('/me/messages', 'POST', {\n subject: args.subject,\n body: { contentType: 'Text', content: args.body },\n toRecipients: [{ emailAddress: { address: args.to } }],\n });\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(data) }],\n };\n },\n );\n\n registerTool(\n 'archive_email',\n 'Move an Outlook email to Archive folder',\n {\n messageId: z.string().describe('Outlook message ID to archive'),\n },\n async (args: { messageId: string }) => {\n const data = await graphRequest(`/me/messages/${args.messageId}/move`, 'POST', {\n destinationId: 'archive',\n });\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(data) }],\n };\n },\n );\n\n // --- Calendar Tools ---\n\n registerTool(\n 'list_events',\n 'List calendar events in a date range',\n {\n startDateTime: z.string().optional().describe('Start of range (ISO 8601)'),\n endDateTime: z.string().optional().describe('End of range (ISO 8601)'),\n top: z.number().optional().default(25).describe('Maximum events'),\n },\n async (args: { startDateTime?: string; endDateTime?: string; top?: number }) => {\n let path = '/me/events?$orderby=start/dateTime';\n path += `&$top=${args.top || 25}`;\n if (args.startDateTime) {\n path += `&$filter=start/dateTime ge '${args.startDateTime}'`;\n if (args.endDateTime) {\n path += ` and end/dateTime le '${args.endDateTime}'`;\n }\n }\n path +=\n '&$select=id,subject,start,end,location,attendees,bodyPreview,webLink,isAllDay,organizer';\n\n const data = (await graphRequest(path)) as { value: unknown[] };\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ events: data.value }),\n },\n ],\n };\n },\n );\n\n registerTool(\n 'get_event',\n 'Get a specific calendar event by ID',\n {\n eventId: z.string().describe('Calendar event ID'),\n },\n async (args: { eventId: string }) => {\n const data = await graphRequest(`/me/events/${args.eventId}`);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(data) }],\n };\n },\n );\n\n // --- Calendar Write Tools ---\n\n registerTool(\n 'create_event',\n 'Create a new calendar event in Outlook',\n {\n subject: z.string().describe('Event title'),\n startDateTime: z.string().describe('Start time (ISO 8601)'),\n endDateTime: z.string().describe('End time (ISO 8601)'),\n body: z.string().optional().describe('Event description'),\n location: z.string().optional().describe('Event location'),\n attendeeEmails: z.array(z.string()).optional().describe('Attendee email addresses'),\n },\n async (args: {\n subject: string;\n startDateTime: string;\n endDateTime: string;\n body?: string;\n location?: string;\n attendeeEmails?: string[];\n }) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const event: Record<string, any> = {\n subject: args.subject,\n start: { dateTime: args.startDateTime, timeZone: 'UTC' },\n end: { dateTime: args.endDateTime, timeZone: 'UTC' },\n };\n if (args.body) event.body = { contentType: 'Text', content: args.body };\n if (args.location) event.location = { displayName: args.location };\n if (args.attendeeEmails) {\n event.attendees = args.attendeeEmails.map((email) => ({\n emailAddress: { address: email },\n type: 'required',\n }));\n }\n\n const data = await graphRequest('/me/events', 'POST', event);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(data) }],\n };\n },\n );\n\n registerTool(\n 'update_event',\n 'Update an existing Outlook calendar event',\n {\n eventId: z.string().describe('Calendar event ID'),\n subject: z.string().optional().describe('New event title'),\n startDateTime: z.string().optional().describe('New start time (ISO 8601)'),\n endDateTime: z.string().optional().describe('New end time (ISO 8601)'),\n body: z.string().optional().describe('New event description'),\n location: z.string().optional().describe('New event location'),\n },\n async (args: {\n eventId: string;\n subject?: string;\n startDateTime?: string;\n endDateTime?: string;\n body?: string;\n location?: string;\n }) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const patch: Record<string, any> = {};\n if (args.subject) patch.subject = args.subject;\n if (args.body) patch.body = { contentType: 'Text', content: args.body };\n if (args.location) patch.location = { displayName: args.location };\n if (args.startDateTime) patch.start = { dateTime: args.startDateTime, timeZone: 'UTC' };\n if (args.endDateTime) patch.end = { dateTime: args.endDateTime, timeZone: 'UTC' };\n\n const data = await graphRequest(`/me/events/${args.eventId}`, 'PATCH', patch);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(data) }],\n };\n },\n );\n\n registerTool(\n 'delete_event',\n 'Delete an Outlook calendar event',\n {\n eventId: z.string().describe('Calendar event ID to delete'),\n },\n async (args: { eventId: string }) => {\n await graphRequest(`/me/events/${args.eventId}`, 'DELETE');\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ deleted: true, eventId: args.eventId }),\n },\n ],\n };\n },\n );\n\n // --- OneDrive Tools ---\n\n registerTool(\n 'search_files',\n 'Search OneDrive files',\n {\n query: z.string().describe('Search query'),\n top: z.number().optional().default(20).describe('Maximum results'),\n },\n async (args: { query: string; top?: number }) => {\n const top = args.top || 20;\n const data = (await graphRequest(\n `/me/drive/root/search(q='${encodeURIComponent(args.query)}')?$top=${top}&$select=id,name,file,size,lastModifiedDateTime,webUrl`,\n )) as { value: unknown[] };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ files: data.value }),\n },\n ],\n };\n },\n );\n\n registerTool(\n 'get_file_content',\n 'Get OneDrive file metadata by item ID',\n {\n itemId: z.string().describe('OneDrive item ID'),\n },\n async (args: { itemId: string }) => {\n const data = await graphRequest(`/me/drive/items/${args.itemId}`);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(data) }],\n };\n },\n );\n\n return {\n server,\n getRegisteredTools() {\n return registeredTools;\n },\n async start() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n },\n };\n}\n\n// CLI entry point\nconst isMainModule =\n process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/\\\\/g, '/'));\nif (isMainModule || process.env.FORGE_MCP_START === 'true') {\n const tokenPath = process.env.FORGE_TOKEN_PATH;\n const clientId = process.env.FORGE_CLIENT_ID;\n const clientSecret = process.env.FORGE_CLIENT_SECRET;\n\n if (!tokenPath || !clientId || !clientSecret) {\n console.error(\n 'Required environment variables: FORGE_TOKEN_PATH, FORGE_CLIENT_ID, FORGE_CLIENT_SECRET',\n );\n process.exit(1);\n }\n\n const mcpServer = createMicrosoft365MCPServer({ tokenPath, clientId, clientSecret });\n mcpServer.start().catch((err) => {\n console.error('Failed to start MCP server:', err);\n process.exit(1);\n });\n}\n","/**\n * Forge Token Manager — reads Forge's OAuthTokens format and handles refresh.\n *\n * Used by @forge/mcp-* packages to get valid access tokens for API calls.\n * Reads from FORGE_TOKEN_PATH, validates with Zod, and refreshes when\n * the token is expired or within 5 minutes of expiry.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { z } from 'zod';\n\n/** Zod schema for Forge's OAuth token file format */\nexport const ForgeOAuthTokensSchema = z.object({\n accessToken: z.string(),\n refreshToken: z.string().optional(),\n expiresAt: z.number(),\n providerId: z.string(),\n connectedAt: z.string(),\n scope: z.string().optional(),\n email: z.string().optional(),\n accountId: z.string().optional(),\n});\n\nexport type ForgeOAuthTokens = z.infer<typeof ForgeOAuthTokensSchema>;\n\nexport interface ForgeTokenManagerOptions {\n /** Path to the Forge OAuth token JSON file */\n tokenPath: string;\n /** OAuth client ID for token refresh */\n clientId: string;\n /** OAuth client secret for token refresh */\n clientSecret: string;\n /** OAuth token endpoint URL for refresh requests */\n tokenUrl: string;\n /** Buffer in ms before expiry to trigger refresh (default: 5 minutes) */\n refreshBufferMs?: number;\n}\n\nexport interface ForgeTokenManager {\n /** Returns a valid access token, refreshing if needed */\n getAccessToken(): Promise<string>;\n /** Returns the current token data, or null if not yet loaded */\n getTokenInfo(): ForgeOAuthTokens | null;\n /** Register a callback for when tokens are refreshed */\n onRefresh(callback: (tokens: ForgeOAuthTokens) => void): void;\n}\n\nconst DEFAULT_REFRESH_BUFFER_MS = 5 * 60 * 1000; // 5 minutes\n\nexport function createForgeTokenManager(options: ForgeTokenManagerOptions): ForgeTokenManager {\n const {\n tokenPath,\n clientId,\n clientSecret,\n tokenUrl,\n refreshBufferMs = DEFAULT_REFRESH_BUFFER_MS,\n } = options;\n\n let cachedTokens: ForgeOAuthTokens | null = null;\n const refreshCallbacks: Array<(tokens: ForgeOAuthTokens) => void> = [];\n\n function isExpiredOrNearExpiry(tokens: ForgeOAuthTokens): boolean {\n return Date.now() >= tokens.expiresAt - refreshBufferMs;\n }\n\n async function readTokenFile(): Promise<ForgeOAuthTokens> {\n let raw: string;\n try {\n raw = await fs.readFile(tokenPath, 'utf-8');\n } catch (err: unknown) {\n if (err && typeof err === 'object' && 'code' in err && err.code === 'ENOENT') {\n throw new Error(`Token file not found: ${tokenPath}`);\n }\n throw err;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid JSON in token file: ${tokenPath}`);\n }\n\n const result = ForgeOAuthTokensSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(`Invalid token file format: ${result.error.message}`);\n }\n\n return result.data;\n }\n\n async function refreshToken(tokens: ForgeOAuthTokens): Promise<ForgeOAuthTokens> {\n if (!tokens.refreshToken) {\n throw new Error('No refresh token available — cannot refresh expired token');\n }\n\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: tokens.refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n });\n\n const response = await fetch(tokenUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed (${response.status}): ${errorText}`);\n }\n\n const data = await response.json();\n\n const refreshedTokens: ForgeOAuthTokens = {\n ...tokens,\n accessToken: data.access_token,\n refreshToken: data.refresh_token || tokens.refreshToken,\n expiresAt: Date.now() + data.expires_in * 1000,\n };\n\n // Write refreshed tokens back to file\n await fs.mkdir(path.dirname(tokenPath), { recursive: true });\n await fs.writeFile(tokenPath, JSON.stringify(refreshedTokens), { mode: 0o600 });\n\n // Notify listeners\n for (const cb of refreshCallbacks) {\n cb(refreshedTokens);\n }\n\n return refreshedTokens;\n }\n\n return {\n async getAccessToken(): Promise<string> {\n if (cachedTokens && !isExpiredOrNearExpiry(cachedTokens)) {\n return cachedTokens.accessToken;\n }\n\n const tokens = cachedTokens || (await readTokenFile());\n\n if (isExpiredOrNearExpiry(tokens)) {\n if (tokens.refreshToken) {\n cachedTokens = await refreshToken(tokens);\n } else {\n // No refresh token — return the access token as-is.\n // Some providers (e.g. Slack bot tokens) issue non-expiring tokens\n // without refresh tokens, so the expiresAt may be unreliable.\n cachedTokens = tokens;\n }\n } else {\n cachedTokens = tokens;\n }\n\n return cachedTokens.accessToken;\n },\n\n getTokenInfo(): ForgeOAuthTokens | null {\n return cachedTokens;\n },\n\n onRefresh(callback: (tokens: ForgeOAuthTokens) => void): void {\n refreshCallbacks.push(callback);\n },\n };\n}\n\n/**\n * Create a ForgeTokenManager from standard environment variables.\n *\n * Expected env vars:\n * - FORGE_TOKEN_PATH: path to the OAuth token JSON file\n * - FORGE_CLIENT_ID: OAuth client ID\n * - FORGE_CLIENT_SECRET: OAuth client secret\n *\n * @param tokenUrl The provider's token endpoint URL\n */\nexport function createForgeTokenManagerFromEnv(tokenUrl: string): ForgeTokenManager {\n const tokenPath = process.env.FORGE_TOKEN_PATH;\n const clientId = process.env.FORGE_CLIENT_ID;\n const clientSecret = process.env.FORGE_CLIENT_SECRET;\n\n if (!tokenPath) throw new Error('FORGE_TOKEN_PATH environment variable is required');\n if (!clientId) throw new Error('FORGE_CLIENT_ID environment variable is required');\n if (!clientSecret) throw new Error('FORGE_CLIENT_SECRET environment variable is required');\n\n return createForgeTokenManager({ tokenPath, clientId, clientSecret, tokenUrl });\n}\n"],"mappings":"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","names":["z","path","options","z"]}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@goforgeit/mcp-microsoft-365",
3
+ "version": "0.4.11",
4
+ "type": "module",
5
+ "description": "Forge MCP server for Microsoft 365 (Outlook, Calendar, OneDrive)",
6
+ "bin": {
7
+ "mcp-microsoft-365": "./dist/index.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "typecheck": "tsc --noEmit",
21
+ "test": "vitest run"
22
+ },
23
+ "dependencies": {
24
+ "@modelcontextprotocol/sdk": "^1.12.1",
25
+ "zod": "^4.2.1"
26
+ },
27
+ "devDependencies": {
28
+ "@forge/shared": "workspace:*",
29
+ "@types/node": "^22.10.2",
30
+ "tsup": "^8.0.0",
31
+ "vitest": "^3.2.4"
32
+ }
33
+ }