@frustrated/ms-graph-mcp 0.1.8 → 0.1.10
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/AGENTS.MD +137 -0
- package/CONTRIBUTING.md +3 -3
- package/LICENSE +21 -21
- package/README.md +95 -95
- package/bun.lock +182 -0
- package/docs/jsr_mcp_ideation.md +83 -83
- package/docs/ms_graph_mcp_spec.md +212 -212
- package/docs/tools/README.md +13 -13
- package/docs/tools/calendar.md +31 -31
- package/docs/tools/mail.md +26 -26
- package/package.json +49 -45
- package/src/auth.ts +194 -194
- package/src/config.ts +52 -48
- package/src/index.ts +77 -80
- package/src/mcp-interface.ts +72 -122
- package/src/tools/calendar.ts +41 -41
- package/src/tools/index.ts +9 -9
- package/src/tools/mail.ts +34 -34
- package/src/utils.ts +21 -20
- package/tsconfig.json +21 -21
- package/.claude/settings.local.json +0 -8
package/src/config.ts
CHANGED
|
@@ -1,48 +1,52 @@
|
|
|
1
|
-
import { promises as fs } from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import * as os from "node:os";
|
|
4
|
-
|
|
5
|
-
const CONFIG_DIR = path.join(os.homedir(), ".ms-graph-mcp");
|
|
6
|
-
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
7
|
-
|
|
8
|
-
interface AppConfig {
|
|
9
|
-
clientId: string;
|
|
10
|
-
tenantId: string;
|
|
11
|
-
enabledTools: string[]; // List of tool names that are enabled
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let appConfig: AppConfig = {
|
|
15
|
-
clientId: "0a74e52a-4d5b-4005-8dad-6b7cf45ec5fe", // Default centralized client ID
|
|
16
|
-
tenantId: "common",
|
|
17
|
-
enabledTools: [],
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export async function loadConfig(): Promise<AppConfig> {
|
|
21
|
-
try {
|
|
22
|
-
const configContent = await fs.readFile(CONFIG_FILE, "utf-8");
|
|
23
|
-
appConfig = { ...appConfig, ...JSON.parse(configContent) };
|
|
24
|
-
} catch (error) {
|
|
25
|
-
// If file doesn't exist or is invalid, use default config
|
|
26
|
-
console.warn(
|
|
27
|
-
"No existing config found or config file is invalid. Using default configuration.",
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
return appConfig;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export async function saveConfig(newConfig: Partial<AppConfig>): Promise<void> {
|
|
34
|
-
appConfig = { ...appConfig, ...newConfig };
|
|
35
|
-
await fs.mkdir(CONFIG_DIR, { recursive: true });
|
|
36
|
-
await fs.writeFile(CONFIG_FILE, JSON.stringify(appConfig, null, 2));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function getConfig(): AppConfig {
|
|
40
|
-
return appConfig;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function isToolEnabled(toolName: string): boolean {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as os from "node:os";
|
|
4
|
+
|
|
5
|
+
const CONFIG_DIR = path.join(os.homedir(), ".ms-graph-mcp");
|
|
6
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
7
|
+
|
|
8
|
+
interface AppConfig {
|
|
9
|
+
clientId: string;
|
|
10
|
+
tenantId: string;
|
|
11
|
+
enabledTools: string[]; // List of tool names that are enabled
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let appConfig: AppConfig = {
|
|
15
|
+
clientId: "0a74e52a-4d5b-4005-8dad-6b7cf45ec5fe", // Default centralized client ID
|
|
16
|
+
tenantId: "common",
|
|
17
|
+
enabledTools: [],
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export async function loadConfig(): Promise<AppConfig> {
|
|
21
|
+
try {
|
|
22
|
+
const configContent = await fs.readFile(CONFIG_FILE, "utf-8");
|
|
23
|
+
appConfig = { ...appConfig, ...JSON.parse(configContent) };
|
|
24
|
+
} catch (error) {
|
|
25
|
+
// If file doesn't exist or is invalid, use default config
|
|
26
|
+
console.warn(
|
|
27
|
+
"No existing config found or config file is invalid. Using default configuration.",
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return appConfig;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function saveConfig(newConfig: Partial<AppConfig>): Promise<void> {
|
|
34
|
+
appConfig = { ...appConfig, ...newConfig };
|
|
35
|
+
await fs.mkdir(CONFIG_DIR, { recursive: true });
|
|
36
|
+
await fs.writeFile(CONFIG_FILE, JSON.stringify(appConfig, null, 2));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getConfig(): AppConfig {
|
|
40
|
+
return appConfig;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function isToolEnabled(toolName: string): boolean {
|
|
44
|
+
// Empty enabledTools means all tools are enabled (no explicit restriction)
|
|
45
|
+
if (appConfig.enabledTools.length === 0) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return appConfig.enabledTools.includes(toolName);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Initialize config on module load
|
|
52
|
+
loadConfig();
|
package/src/index.ts
CHANGED
|
@@ -1,80 +1,77 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Command } from "@commander-js/extra-typings";
|
|
3
|
-
import { initAuth, revokeAuth, getAuthStatus } from "./auth.ts";
|
|
4
|
-
import { getConfig, saveConfig } from "./config.ts";
|
|
5
|
-
import { startMcpServer } from "./mcp-interface.ts";
|
|
6
|
-
|
|
7
|
-
const program = new Command();
|
|
8
|
-
|
|
9
|
-
program
|
|
10
|
-
.name("ms-graph-mcp")
|
|
11
|
-
.description("CLI for JSR-based Microsoft Graph MCP package")
|
|
12
|
-
.version("0.1.0");
|
|
13
|
-
|
|
14
|
-
program
|
|
15
|
-
.command("init")
|
|
16
|
-
.description("Initialize authentication with Microsoft Graph")
|
|
17
|
-
.action(async () => {
|
|
18
|
-
try {
|
|
19
|
-
await initAuth();
|
|
20
|
-
console.log("Authentication process completed.");
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.error("Authentication failed:", error instanceof Error ? error.message : String(error));
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
program
|
|
28
|
-
.command("revoke")
|
|
29
|
-
.description("Revoke Microsoft Graph authentication and clear tokens")
|
|
30
|
-
.action(async () => {
|
|
31
|
-
try {
|
|
32
|
-
await revokeAuth();
|
|
33
|
-
console.log("Authentication revoked successfully.");
|
|
34
|
-
} catch (error) {
|
|
35
|
-
console.error("Failed to revoke authentication:", error instanceof Error ? error.message : String(error));
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
program
|
|
41
|
-
.command("permissions")
|
|
42
|
-
.description(
|
|
43
|
-
"Display current authentication status and configured permissions",
|
|
44
|
-
)
|
|
45
|
-
.action(async () => {
|
|
46
|
-
try {
|
|
47
|
-
const authStatus = await getAuthStatus();
|
|
48
|
-
const config = getConfig();
|
|
49
|
-
console.log("--- Microsoft Graph MCP Status ---");
|
|
50
|
-
console.log(`Client ID: ${authStatus.clientId}`);
|
|
51
|
-
console.log(`Tenant ID: ${authStatus.tenantId}`);
|
|
52
|
-
console.log(
|
|
53
|
-
`Authenticated: ${authStatus.isAuthenticated ? "Yes" : "No"}`,
|
|
54
|
-
);
|
|
55
|
-
console.log("\nEnabled Tools:");
|
|
56
|
-
if (config.enabledTools.length > 0) {
|
|
57
|
-
config.enabledTools.forEach((tool) => console.log(`- ${tool}`));
|
|
58
|
-
} else {
|
|
59
|
-
console.log(
|
|
60
|
-
"No specific tools are explicitly enabled in config. All available tools will be used.",
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
console.log("----------------------------------");
|
|
64
|
-
} catch (error) {
|
|
65
|
-
console.error("Failed to retrieve status:", error instanceof Error ? error.message : String(error));
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
program
|
|
71
|
-
.command("run")
|
|
72
|
-
.description("Start the MCP server to listen for commands via stdin/stdout")
|
|
73
|
-
.action(async () => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
program.parse(process.argv);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "@commander-js/extra-typings";
|
|
3
|
+
import { initAuth, revokeAuth, getAuthStatus } from "./auth.ts";
|
|
4
|
+
import { getConfig, saveConfig } from "./config.ts";
|
|
5
|
+
import { startMcpServer } from "./mcp-interface.ts";
|
|
6
|
+
|
|
7
|
+
const program = new Command();
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.name("ms-graph-mcp")
|
|
11
|
+
.description("CLI for JSR-based Microsoft Graph MCP package")
|
|
12
|
+
.version("0.1.0");
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.command("init")
|
|
16
|
+
.description("Initialize authentication with Microsoft Graph")
|
|
17
|
+
.action(async () => {
|
|
18
|
+
try {
|
|
19
|
+
await initAuth();
|
|
20
|
+
console.log("Authentication process completed.");
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error("Authentication failed:", error instanceof Error ? error.message : String(error));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
program
|
|
28
|
+
.command("revoke")
|
|
29
|
+
.description("Revoke Microsoft Graph authentication and clear tokens")
|
|
30
|
+
.action(async () => {
|
|
31
|
+
try {
|
|
32
|
+
await revokeAuth();
|
|
33
|
+
console.log("Authentication revoked successfully.");
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error("Failed to revoke authentication:", error instanceof Error ? error.message : String(error));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
program
|
|
41
|
+
.command("permissions")
|
|
42
|
+
.description(
|
|
43
|
+
"Display current authentication status and configured permissions",
|
|
44
|
+
)
|
|
45
|
+
.action(async () => {
|
|
46
|
+
try {
|
|
47
|
+
const authStatus = await getAuthStatus();
|
|
48
|
+
const config = getConfig();
|
|
49
|
+
console.log("--- Microsoft Graph MCP Status ---");
|
|
50
|
+
console.log(`Client ID: ${authStatus.clientId}`);
|
|
51
|
+
console.log(`Tenant ID: ${authStatus.tenantId}`);
|
|
52
|
+
console.log(
|
|
53
|
+
`Authenticated: ${authStatus.isAuthenticated ? "Yes" : "No"}`,
|
|
54
|
+
);
|
|
55
|
+
console.log("\nEnabled Tools:");
|
|
56
|
+
if (config.enabledTools.length > 0) {
|
|
57
|
+
config.enabledTools.forEach((tool) => console.log(`- ${tool}`));
|
|
58
|
+
} else {
|
|
59
|
+
console.log(
|
|
60
|
+
"No specific tools are explicitly enabled in config. All available tools will be used.",
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
console.log("----------------------------------");
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("Failed to retrieve status:", error instanceof Error ? error.message : String(error));
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
program
|
|
71
|
+
.command("run")
|
|
72
|
+
.description("Start the MCP server to listen for commands via stdin/stdout")
|
|
73
|
+
.action(async () => {
|
|
74
|
+
await startMcpServer();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
program.parse(process.argv);
|
package/src/mcp-interface.ts
CHANGED
|
@@ -1,122 +1,72 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function startMcpServer() {
|
|
75
|
-
log('MCP server started. Listening for commands on stdin...');
|
|
76
|
-
|
|
77
|
-
process.stdin.setEncoding('utf8');
|
|
78
|
-
|
|
79
|
-
let buffer = '';
|
|
80
|
-
process.stdin.on('data', async (chunk) => {
|
|
81
|
-
buffer += chunk;
|
|
82
|
-
let newlineIndex;
|
|
83
|
-
while ((newlineIndex = buffer.indexOf('\n')) !== -1) {
|
|
84
|
-
const line = buffer.substring(0, newlineIndex).trim();
|
|
85
|
-
buffer = buffer.substring(newlineIndex + 1);
|
|
86
|
-
|
|
87
|
-
if (line) {
|
|
88
|
-
try {
|
|
89
|
-
const request: McpRequest = JSON.parse(line);
|
|
90
|
-
if (request.type === 'request' && request.id && request.tool) {
|
|
91
|
-
const response = await processMcpRequest(request);
|
|
92
|
-
process.stdout.write(JSON.stringify(response) + '\n');
|
|
93
|
-
} else {
|
|
94
|
-
error('Invalid MCP request format:', new Error(line));
|
|
95
|
-
process.stdout.write(JSON.stringify({
|
|
96
|
-
type: 'response',
|
|
97
|
-
id: request.id || 'unknown',
|
|
98
|
-
status: 'error',
|
|
99
|
-
error: { code: 'INVALID_REQUEST', message: 'Invalid MCP request format.' },
|
|
100
|
-
}) + '\n');
|
|
101
|
-
}
|
|
102
|
-
} catch (parseError: any) {
|
|
103
|
-
error('Failed to parse stdin input as JSON:', parseError);
|
|
104
|
-
process.stdout.write(JSON.stringify({
|
|
105
|
-
type: 'response',
|
|
106
|
-
id: 'unknown',
|
|
107
|
-
status: 'error',
|
|
108
|
-
error: { code: 'JSON_PARSE_ERROR', message: 'Invalid JSON input.' },
|
|
109
|
-
}) + '\n');
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
process.stdin.on('end', () => {
|
|
116
|
-
log('Stdin closed. MCP server shutting down.');
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
process.stdin.on('error', (err) => {
|
|
120
|
-
error('Stdin error:', err);
|
|
121
|
-
});
|
|
122
|
-
}
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { getAccessToken } from './auth.ts';
|
|
5
|
+
import { isToolEnabled } from './config.ts';
|
|
6
|
+
import { log } from './utils.ts';
|
|
7
|
+
import { Client } from '@microsoft/microsoft-graph-client';
|
|
8
|
+
import * as mail from './tools/mail.ts';
|
|
9
|
+
import * as calendar from './tools/calendar.ts';
|
|
10
|
+
|
|
11
|
+
function buildGraphClient(accessToken: string): Client {
|
|
12
|
+
return Client.init({
|
|
13
|
+
authProvider: (done) => done(null, accessToken),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function startMcpServer(): Promise<void> {
|
|
18
|
+
const server = new McpServer({
|
|
19
|
+
name: 'ms-graph-mcp',
|
|
20
|
+
version: '0.1.10',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (isToolEnabled('mail.list_messages')) {
|
|
24
|
+
server.tool(
|
|
25
|
+
'mail.list_messages',
|
|
26
|
+
'List email messages from the signed-in user\'s mailbox',
|
|
27
|
+
{
|
|
28
|
+
folderId: z.string().optional().describe('Mail folder ID (defaults to Inbox)'),
|
|
29
|
+
top: z.number().int().min(1).optional().describe('Maximum number of messages to return'),
|
|
30
|
+
filter: z.string().optional().describe('OData $filter expression'),
|
|
31
|
+
},
|
|
32
|
+
async ({ folderId, top, filter }) => {
|
|
33
|
+
const token = await getAccessToken();
|
|
34
|
+
const result = await mail.listMessages(buildGraphClient(token), { folderId, top, filter });
|
|
35
|
+
return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] };
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (isToolEnabled('calendar.create_event')) {
|
|
41
|
+
server.tool(
|
|
42
|
+
'calendar.create_event',
|
|
43
|
+
'Create a new event in the signed-in user\'s calendar',
|
|
44
|
+
{
|
|
45
|
+
subject: z.string().describe('Event title'),
|
|
46
|
+
start: z.object({
|
|
47
|
+
dateTime: z.string().describe('ISO 8601 date-time string'),
|
|
48
|
+
timeZone: z.string().describe('IANA timezone name, e.g. "America/New_York"'),
|
|
49
|
+
}),
|
|
50
|
+
end: z.object({
|
|
51
|
+
dateTime: z.string().describe('ISO 8601 date-time string'),
|
|
52
|
+
timeZone: z.string().describe('IANA timezone name'),
|
|
53
|
+
}),
|
|
54
|
+
content: z.string().optional().describe('HTML body of the event'),
|
|
55
|
+
attendees: z.array(z.object({
|
|
56
|
+
emailAddress: z.string().email(),
|
|
57
|
+
type: z.enum(['required', 'optional']),
|
|
58
|
+
})).optional().describe('List of attendees'),
|
|
59
|
+
location: z.string().optional().describe('Event location display name'),
|
|
60
|
+
},
|
|
61
|
+
async (input) => {
|
|
62
|
+
const token = await getAccessToken();
|
|
63
|
+
const result = await calendar.createEvent(buildGraphClient(token), input);
|
|
64
|
+
return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] };
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const transport = new StdioServerTransport();
|
|
70
|
+
await server.connect(transport);
|
|
71
|
+
log('MCP server started (JSON-RPC 2.0 over stdio). Listening for commands...');
|
|
72
|
+
}
|
package/src/tools/calendar.ts
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import { Client } from '@microsoft/microsoft-graph-client';
|
|
2
|
-
import { log, error } from '../utils.ts';
|
|
3
|
-
|
|
4
|
-
export async function createEvent(graphClient: Client, input: {
|
|
5
|
-
subject: string;
|
|
6
|
-
start: { dateTime: string; timeZone: string };
|
|
7
|
-
end: { dateTime: string; timeZone: string };
|
|
8
|
-
content?: string;
|
|
9
|
-
attendees?: Array<{ emailAddress: string; type: 'required' | 'optional' }>;
|
|
10
|
-
location?: string;
|
|
11
|
-
}): Promise<any> {
|
|
12
|
-
try {
|
|
13
|
-
const event = {
|
|
14
|
-
subject: input.subject,
|
|
15
|
-
start: input.start,
|
|
16
|
-
end: input.end,
|
|
17
|
-
body: input.content ? { contentType: 'HTML', content: input.content } : undefined,
|
|
18
|
-
attendees: input.attendees?.map(att => ({
|
|
19
|
-
emailAddress: { address: att.emailAddress },
|
|
20
|
-
type: att.type,
|
|
21
|
-
})),
|
|
22
|
-
location: input.location ? { displayName: input.location } : undefined,
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const response = await graphClient.api('/me/events').post(event);
|
|
26
|
-
log(`Created calendar event: ${response.subject} (ID: ${response.id})`);
|
|
27
|
-
return {
|
|
28
|
-
id: response.id,
|
|
29
|
-
webLink: response.webLink,
|
|
30
|
-
status: 'created',
|
|
31
|
-
};
|
|
32
|
-
} catch (err: any) {
|
|
33
|
-
error('Error creating calendar event:', err);
|
|
34
|
-
return {
|
|
35
|
-
id: null,
|
|
36
|
-
webLink: null,
|
|
37
|
-
status: 'failed',
|
|
38
|
-
errorMessage: err.message,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
1
|
+
import { Client } from '@microsoft/microsoft-graph-client';
|
|
2
|
+
import { log, error } from '../utils.ts';
|
|
3
|
+
|
|
4
|
+
export async function createEvent(graphClient: Client, input: {
|
|
5
|
+
subject: string;
|
|
6
|
+
start: { dateTime: string; timeZone: string };
|
|
7
|
+
end: { dateTime: string; timeZone: string };
|
|
8
|
+
content?: string;
|
|
9
|
+
attendees?: Array<{ emailAddress: string; type: 'required' | 'optional' }>;
|
|
10
|
+
location?: string;
|
|
11
|
+
}): Promise<any> {
|
|
12
|
+
try {
|
|
13
|
+
const event = {
|
|
14
|
+
subject: input.subject,
|
|
15
|
+
start: input.start,
|
|
16
|
+
end: input.end,
|
|
17
|
+
body: input.content ? { contentType: 'HTML', content: input.content } : undefined,
|
|
18
|
+
attendees: input.attendees?.map(att => ({
|
|
19
|
+
emailAddress: { address: att.emailAddress },
|
|
20
|
+
type: att.type,
|
|
21
|
+
})),
|
|
22
|
+
location: input.location ? { displayName: input.location } : undefined,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const response = await graphClient.api('/me/events').post(event);
|
|
26
|
+
log(`Created calendar event: ${response.subject} (ID: ${response.id})`);
|
|
27
|
+
return {
|
|
28
|
+
id: response.id,
|
|
29
|
+
webLink: response.webLink,
|
|
30
|
+
status: 'created',
|
|
31
|
+
};
|
|
32
|
+
} catch (err: any) {
|
|
33
|
+
error('Error creating calendar event:', err);
|
|
34
|
+
return {
|
|
35
|
+
id: null,
|
|
36
|
+
webLink: null,
|
|
37
|
+
status: 'failed',
|
|
38
|
+
errorMessage: err.message,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/tools/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import * as mail from './mail.ts';
|
|
2
|
-
import * as calendar from './calendar.ts';
|
|
3
|
-
// import * as onedrive from './onedrive'; // Placeholder for future tools
|
|
4
|
-
|
|
5
|
-
export const tools = {
|
|
6
|
-
'mail.list_messages': mail.listMessages,
|
|
7
|
-
'calendar.create_event': calendar.createEvent,
|
|
8
|
-
// 'onedrive.list_files': onedrive.listFiles,
|
|
9
|
-
};
|
|
1
|
+
import * as mail from './mail.ts';
|
|
2
|
+
import * as calendar from './calendar.ts';
|
|
3
|
+
// import * as onedrive from './onedrive'; // Placeholder for future tools
|
|
4
|
+
|
|
5
|
+
export const tools = {
|
|
6
|
+
'mail.list_messages': mail.listMessages,
|
|
7
|
+
'calendar.create_event': calendar.createEvent,
|
|
8
|
+
// 'onedrive.list_files': onedrive.listFiles,
|
|
9
|
+
};
|
package/src/tools/mail.ts
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import { Client } from '@microsoft/microsoft-graph-client';
|
|
2
|
-
import { log, error } from '../utils.ts';
|
|
3
|
-
|
|
4
|
-
export async function listMessages(graphClient: Client, input: { folderId?: string; top?: number; filter?: string }): Promise<any> {
|
|
5
|
-
try {
|
|
6
|
-
let request = graphClient.api(input.folderId ? `/me/mailFolders/${input.folderId}/messages` :
|
|
7
|
-
'/me/messages');
|
|
8
|
-
|
|
9
|
-
if (input.top) {
|
|
10
|
-
request = request.top(input.top);
|
|
11
|
-
}
|
|
12
|
-
if (input.filter) {
|
|
13
|
-
request = request.filter(input.filter);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const response = await request.select('id,subject,from,receivedDateTime,isRead,bodyPreview,webLink').get();
|
|
17
|
-
log(`Listed ${response.value.length} messages.`);
|
|
18
|
-
return {
|
|
19
|
-
messages: response.value.map((msg: any) => ({
|
|
20
|
-
id: msg.id,
|
|
21
|
-
subject: msg.subject,
|
|
22
|
-
from: msg.from,
|
|
23
|
-
receivedDateTime: msg.receivedDateTime,
|
|
24
|
-
isRead: msg.isRead,
|
|
25
|
-
bodyPreview: msg.bodyPreview,
|
|
26
|
-
webLink: msg.webLink,
|
|
27
|
-
})),
|
|
28
|
-
nextLink: response['@odata.nextLink'],
|
|
29
|
-
};
|
|
30
|
-
} catch (err: any) {
|
|
31
|
-
error('Error listing messages:', err);
|
|
32
|
-
throw err;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
1
|
+
import { Client } from '@microsoft/microsoft-graph-client';
|
|
2
|
+
import { log, error } from '../utils.ts';
|
|
3
|
+
|
|
4
|
+
export async function listMessages(graphClient: Client, input: { folderId?: string; top?: number; filter?: string }): Promise<any> {
|
|
5
|
+
try {
|
|
6
|
+
let request = graphClient.api(input.folderId ? `/me/mailFolders/${input.folderId}/messages` :
|
|
7
|
+
'/me/messages');
|
|
8
|
+
|
|
9
|
+
if (input.top) {
|
|
10
|
+
request = request.top(input.top);
|
|
11
|
+
}
|
|
12
|
+
if (input.filter) {
|
|
13
|
+
request = request.filter(input.filter);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const response = await request.select('id,subject,from,receivedDateTime,isRead,bodyPreview,webLink').get();
|
|
17
|
+
log(`Listed ${response.value.length} messages.`);
|
|
18
|
+
return {
|
|
19
|
+
messages: response.value.map((msg: any) => ({
|
|
20
|
+
id: msg.id,
|
|
21
|
+
subject: msg.subject,
|
|
22
|
+
from: msg.from,
|
|
23
|
+
receivedDateTime: msg.receivedDateTime,
|
|
24
|
+
isRead: msg.isRead,
|
|
25
|
+
bodyPreview: msg.bodyPreview,
|
|
26
|
+
webLink: msg.webLink,
|
|
27
|
+
})),
|
|
28
|
+
nextLink: response['@odata.nextLink'],
|
|
29
|
+
};
|
|
30
|
+
} catch (err: any) {
|
|
31
|
+
error('Error listing messages:', err);
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
}
|