outlook-cli 1.2.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/CLI.md +89 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +104 -0
- package/README.md +994 -0
- package/auth/index.js +36 -0
- package/auth/oauth-server.js +139 -0
- package/auth/token-manager.js +199 -0
- package/auth/token-storage.js +282 -0
- package/auth/tools.js +127 -0
- package/calendar/accept.js +64 -0
- package/calendar/cancel.js +64 -0
- package/calendar/create.js +69 -0
- package/calendar/decline.js +64 -0
- package/calendar/delete.js +59 -0
- package/calendar/index.js +123 -0
- package/calendar/list.js +77 -0
- package/cli.js +1349 -0
- package/config.js +84 -0
- package/docs/PROJECT-STRUCTURE.md +52 -0
- package/docs/PUBLISHING.md +86 -0
- package/docs/REFERENCE.md +679 -0
- package/email/folder-utils.js +171 -0
- package/email/index.js +157 -0
- package/email/list.js +89 -0
- package/email/mark-as-read.js +101 -0
- package/email/read.js +128 -0
- package/email/search.js +282 -0
- package/email/send.js +120 -0
- package/folder/create.js +124 -0
- package/folder/index.js +78 -0
- package/folder/list.js +264 -0
- package/folder/move.js +163 -0
- package/index.js +136 -0
- package/outlook-auth-server.js +305 -0
- package/package.json +76 -0
- package/rules/create.js +248 -0
- package/rules/index.js +177 -0
- package/rules/list.js +202 -0
- package/tool-registry.js +54 -0
- package/utils/graph-api.js +120 -0
- package/utils/mock-data.js +145 -0
- package/utils/odata-helpers.js +40 -0
package/auth/tools.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication-related tools for the Outlook MCP server
|
|
3
|
+
*/
|
|
4
|
+
const config = require('../config');
|
|
5
|
+
const tokenManager = require('./token-manager');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* About tool handler
|
|
9
|
+
* @returns {object} - MCP response
|
|
10
|
+
*/
|
|
11
|
+
async function handleAbout() {
|
|
12
|
+
return {
|
|
13
|
+
content: [{
|
|
14
|
+
type: "text",
|
|
15
|
+
text: `outlook-cli v${config.SERVER_VERSION}\n\nProduction-ready Outlook CLI and MCP server powered by Microsoft Graph API.`
|
|
16
|
+
}]
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Authentication tool handler
|
|
22
|
+
* @param {object} args - Tool arguments
|
|
23
|
+
* @returns {object} - MCP response
|
|
24
|
+
*/
|
|
25
|
+
async function handleAuthenticate(args) {
|
|
26
|
+
const force = args && args.force === true;
|
|
27
|
+
|
|
28
|
+
// For test mode, create a test token
|
|
29
|
+
if (config.USE_TEST_MODE) {
|
|
30
|
+
// Create a test token with a 1-hour expiry
|
|
31
|
+
tokenManager.createTestTokens();
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
content: [{
|
|
35
|
+
type: "text",
|
|
36
|
+
text: 'Successfully authenticated with Microsoft Graph API (test mode)'
|
|
37
|
+
}]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (force) {
|
|
42
|
+
tokenManager.clearTokenCache();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!config.AUTH_CONFIG.clientId) {
|
|
46
|
+
return {
|
|
47
|
+
content: [{
|
|
48
|
+
type: "text",
|
|
49
|
+
text: "Client ID is not configured. Set OUTLOOK_CLIENT_ID or MS_CLIENT_ID before authenticating."
|
|
50
|
+
}]
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// For real authentication, generate an auth URL and instruct the user to visit it
|
|
55
|
+
const authUrl = `${config.AUTH_CONFIG.authServerUrl}/auth?client_id=${config.AUTH_CONFIG.clientId}`;
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
content: [{
|
|
59
|
+
type: "text",
|
|
60
|
+
text: `Authentication required. Please visit the following URL to authenticate with Microsoft: ${authUrl}\n\nAfter authentication, you will be redirected back to this application.`
|
|
61
|
+
}]
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Check authentication status tool handler
|
|
67
|
+
* @returns {object} - MCP response
|
|
68
|
+
*/
|
|
69
|
+
async function handleCheckAuthStatus() {
|
|
70
|
+
const accessToken = await tokenManager.getValidAccessToken();
|
|
71
|
+
|
|
72
|
+
if (!accessToken) {
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: "text", text: "Not authenticated" }]
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: "Authenticated and ready" }]
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Tool definitions
|
|
84
|
+
const authTools = [
|
|
85
|
+
{
|
|
86
|
+
name: "about",
|
|
87
|
+
description: "Returns information about this Outlook Assistant server",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: "object",
|
|
90
|
+
properties: {},
|
|
91
|
+
required: []
|
|
92
|
+
},
|
|
93
|
+
handler: handleAbout
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "authenticate",
|
|
97
|
+
description: "Authenticate with Microsoft Graph API to access Outlook data",
|
|
98
|
+
inputSchema: {
|
|
99
|
+
type: "object",
|
|
100
|
+
properties: {
|
|
101
|
+
force: {
|
|
102
|
+
type: "boolean",
|
|
103
|
+
description: "Force re-authentication even if already authenticated"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
required: []
|
|
107
|
+
},
|
|
108
|
+
handler: handleAuthenticate
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "check-auth-status",
|
|
112
|
+
description: "Check the current authentication status with Microsoft Graph API",
|
|
113
|
+
inputSchema: {
|
|
114
|
+
type: "object",
|
|
115
|
+
properties: {},
|
|
116
|
+
required: []
|
|
117
|
+
},
|
|
118
|
+
handler: handleCheckAuthStatus
|
|
119
|
+
}
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
module.exports = {
|
|
123
|
+
authTools,
|
|
124
|
+
handleAbout,
|
|
125
|
+
handleAuthenticate,
|
|
126
|
+
handleCheckAuthStatus
|
|
127
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accept event functionality
|
|
3
|
+
*/
|
|
4
|
+
const { callGraphAPI } = require('../utils/graph-api');
|
|
5
|
+
const { ensureAuthenticated } = require('../auth');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Accept event handler
|
|
9
|
+
* @param {object} args - Tool arguments
|
|
10
|
+
* @returns {object} - MCP response
|
|
11
|
+
*/
|
|
12
|
+
async function handleAcceptEvent(args) {
|
|
13
|
+
const { eventId, comment } = args;
|
|
14
|
+
|
|
15
|
+
if (!eventId) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: "Event ID is required to accept an event."
|
|
20
|
+
}]
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Get access token
|
|
26
|
+
const accessToken = await ensureAuthenticated();
|
|
27
|
+
|
|
28
|
+
// Build API endpoint
|
|
29
|
+
const endpoint = `me/events/${eventId}/accept`;
|
|
30
|
+
|
|
31
|
+
// Request body
|
|
32
|
+
const body = {
|
|
33
|
+
comment: comment || "Accepted via API"
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Make API call
|
|
37
|
+
await callGraphAPI(accessToken, 'POST', endpoint, body);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
content: [{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: `Event with ID ${eventId} has been successfully accepted.`
|
|
43
|
+
}]
|
|
44
|
+
};
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (error.message === 'Authentication required') {
|
|
47
|
+
return {
|
|
48
|
+
content: [{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: "Authentication required. Please use the 'authenticate' tool first."
|
|
51
|
+
}]
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
content: [{
|
|
57
|
+
type: "text",
|
|
58
|
+
text: `Error accepting event: ${error.message}`
|
|
59
|
+
}]
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = handleAcceptEvent;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cancel event functionality
|
|
3
|
+
*/
|
|
4
|
+
const { callGraphAPI } = require('../utils/graph-api');
|
|
5
|
+
const { ensureAuthenticated } = require('../auth');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Cancel event handler
|
|
9
|
+
* @param {object} args - Tool arguments
|
|
10
|
+
* @returns {object} - MCP response
|
|
11
|
+
*/
|
|
12
|
+
async function handleCancelEvent(args) {
|
|
13
|
+
const { eventId, comment } = args;
|
|
14
|
+
|
|
15
|
+
if (!eventId) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: "Event ID is required to cancel an event."
|
|
20
|
+
}]
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Get access token
|
|
26
|
+
const accessToken = await ensureAuthenticated();
|
|
27
|
+
|
|
28
|
+
// Build API endpoint
|
|
29
|
+
const endpoint = `me/events/${eventId}/cancel`;
|
|
30
|
+
|
|
31
|
+
// Request body
|
|
32
|
+
const body = {
|
|
33
|
+
comment: comment || "Cancelled via API"
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Make API call
|
|
37
|
+
await callGraphAPI(accessToken, 'POST', endpoint, body);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
content: [{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: `Event with ID ${eventId} has been successfully cancelled.`
|
|
43
|
+
}]
|
|
44
|
+
};
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (error.message === 'Authentication required') {
|
|
47
|
+
return {
|
|
48
|
+
content: [{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: "Authentication required. Please use the 'authenticate' tool first."
|
|
51
|
+
}]
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
content: [{
|
|
57
|
+
type: "text",
|
|
58
|
+
text: `Error cancelling event: ${error.message}`
|
|
59
|
+
}]
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = handleCancelEvent;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create event functionality
|
|
3
|
+
*/
|
|
4
|
+
const { callGraphAPI } = require('../utils/graph-api');
|
|
5
|
+
const { ensureAuthenticated } = require('../auth');
|
|
6
|
+
const { DEFAULT_TIMEZONE } = require('../config');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Create event handler
|
|
10
|
+
* @param {object} args - Tool arguments
|
|
11
|
+
* @returns {object} - MCP response
|
|
12
|
+
*/
|
|
13
|
+
async function handleCreateEvent(args) {
|
|
14
|
+
const { subject, start, end, attendees, body } = args;
|
|
15
|
+
|
|
16
|
+
if (!subject || !start || !end) {
|
|
17
|
+
return {
|
|
18
|
+
content: [{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: "Subject, start, and end times are required to create an event."
|
|
21
|
+
}]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
// Get access token
|
|
27
|
+
const accessToken = await ensureAuthenticated();
|
|
28
|
+
|
|
29
|
+
// Build API endpoint
|
|
30
|
+
const endpoint = `me/events`;
|
|
31
|
+
|
|
32
|
+
// Request body
|
|
33
|
+
const bodyContent = {
|
|
34
|
+
subject,
|
|
35
|
+
start: { dateTime: start.dateTime || start, timeZone: start.timeZone || DEFAULT_TIMEZONE },
|
|
36
|
+
end: { dateTime: end.dateTime || end, timeZone: end.timeZone || DEFAULT_TIMEZONE },
|
|
37
|
+
attendees: attendees?.map(email => ({ emailAddress: { address: email }, type: "required" })),
|
|
38
|
+
body: { contentType: "HTML", content: body || "" }
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Make API call
|
|
42
|
+
const response = await callGraphAPI(accessToken, 'POST', endpoint, bodyContent);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
content: [{
|
|
46
|
+
type: "text",
|
|
47
|
+
text: `Event '${subject}' has been successfully created.`
|
|
48
|
+
}]
|
|
49
|
+
};
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (error.message === 'Authentication required') {
|
|
52
|
+
return {
|
|
53
|
+
content: [{
|
|
54
|
+
type: "text",
|
|
55
|
+
text: "Authentication required. Please use the 'authenticate' tool first."
|
|
56
|
+
}]
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
content: [{
|
|
62
|
+
type: "text",
|
|
63
|
+
text: `Error creating event: ${error.message}`
|
|
64
|
+
}]
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = handleCreateEvent;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decline event functionality
|
|
3
|
+
*/
|
|
4
|
+
const { callGraphAPI } = require('../utils/graph-api');
|
|
5
|
+
const { ensureAuthenticated } = require('../auth');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Decline event handler
|
|
9
|
+
* @param {object} args - Tool arguments
|
|
10
|
+
* @returns {object} - MCP response
|
|
11
|
+
*/
|
|
12
|
+
async function handleDeclineEvent(args) {
|
|
13
|
+
const { eventId, comment } = args;
|
|
14
|
+
|
|
15
|
+
if (!eventId) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: "Event ID is required to decline an event."
|
|
20
|
+
}]
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Get access token
|
|
26
|
+
const accessToken = await ensureAuthenticated();
|
|
27
|
+
|
|
28
|
+
// Build API endpoint
|
|
29
|
+
const endpoint = `me/events/${eventId}/decline`;
|
|
30
|
+
|
|
31
|
+
// Request body
|
|
32
|
+
const body = {
|
|
33
|
+
comment: comment || "Declined via API"
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Make API call
|
|
37
|
+
await callGraphAPI(accessToken, 'POST', endpoint, body);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
content: [{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: `Event with ID ${eventId} has been successfully declined.`
|
|
43
|
+
}]
|
|
44
|
+
};
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (error.message === 'Authentication required') {
|
|
47
|
+
return {
|
|
48
|
+
content: [{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: "Authentication required. Please use the 'authenticate' tool first."
|
|
51
|
+
}]
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
content: [{
|
|
57
|
+
type: "text",
|
|
58
|
+
text: `Error declining event: ${error.message}`
|
|
59
|
+
}]
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = handleDeclineEvent;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delete event functionality
|
|
3
|
+
*/
|
|
4
|
+
const { callGraphAPI } = require('../utils/graph-api');
|
|
5
|
+
const { ensureAuthenticated } = require('../auth');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Delete event handler
|
|
9
|
+
* @param {object} args - Tool arguments
|
|
10
|
+
* @returns {object} - MCP response
|
|
11
|
+
*/
|
|
12
|
+
async function handleDeleteEvent(args) {
|
|
13
|
+
const { eventId } = args;
|
|
14
|
+
|
|
15
|
+
if (!eventId) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: "Event ID is required to delete an event."
|
|
20
|
+
}]
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Get access token
|
|
26
|
+
const accessToken = await ensureAuthenticated();
|
|
27
|
+
|
|
28
|
+
// Build API endpoint
|
|
29
|
+
const endpoint = `me/events/${eventId}`;
|
|
30
|
+
|
|
31
|
+
// Make API call
|
|
32
|
+
await callGraphAPI(accessToken, 'DELETE', endpoint);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
content: [{
|
|
36
|
+
type: "text",
|
|
37
|
+
text: `Event with ID ${eventId} has been successfully deleted.`
|
|
38
|
+
}]
|
|
39
|
+
};
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error.message === 'Authentication required') {
|
|
42
|
+
return {
|
|
43
|
+
content: [{
|
|
44
|
+
type: "text",
|
|
45
|
+
text: "Authentication required. Please use the 'authenticate' tool first."
|
|
46
|
+
}]
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
content: [{
|
|
52
|
+
type: "text",
|
|
53
|
+
text: `Error deleting event: ${error.message}`
|
|
54
|
+
}]
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = handleDeleteEvent;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar module for Outlook MCP server
|
|
3
|
+
*/
|
|
4
|
+
const handleListEvents = require('./list');
|
|
5
|
+
const handleDeclineEvent = require('./decline');
|
|
6
|
+
const handleCreateEvent = require('./create');
|
|
7
|
+
const handleCancelEvent = require('./cancel');
|
|
8
|
+
const handleDeleteEvent = require('./delete');
|
|
9
|
+
|
|
10
|
+
// Calendar tool definitions
|
|
11
|
+
const calendarTools = [
|
|
12
|
+
{
|
|
13
|
+
name: "list-events",
|
|
14
|
+
description: "Lists upcoming events from your calendar",
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
count: {
|
|
19
|
+
type: "number",
|
|
20
|
+
description: "Number of events to retrieve (default: 10, max: 50)"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
required: []
|
|
24
|
+
},
|
|
25
|
+
handler: handleListEvents
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "decline-event",
|
|
29
|
+
description: "Declines a calendar event",
|
|
30
|
+
inputSchema: {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {
|
|
33
|
+
eventId: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "The ID of the event to decline"
|
|
36
|
+
},
|
|
37
|
+
comment: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description: "Optional comment for declining the event"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
required: ["eventId"]
|
|
43
|
+
},
|
|
44
|
+
handler: handleDeclineEvent
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "create-event",
|
|
48
|
+
description: "Creates a new calendar event",
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
subject: {
|
|
53
|
+
type: "string",
|
|
54
|
+
description: "The subject of the event"
|
|
55
|
+
},
|
|
56
|
+
start: {
|
|
57
|
+
type: "string",
|
|
58
|
+
description: "The start time of the event in ISO 8601 format"
|
|
59
|
+
},
|
|
60
|
+
end: {
|
|
61
|
+
type: "string",
|
|
62
|
+
description: "The end time of the event in ISO 8601 format"
|
|
63
|
+
},
|
|
64
|
+
attendees: {
|
|
65
|
+
type: "array",
|
|
66
|
+
items: {
|
|
67
|
+
type: "string"
|
|
68
|
+
},
|
|
69
|
+
description: "List of attendee email addresses"
|
|
70
|
+
},
|
|
71
|
+
body: {
|
|
72
|
+
type: "string",
|
|
73
|
+
description: "Optional body content for the event"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
required: ["subject", "start", "end"]
|
|
77
|
+
},
|
|
78
|
+
handler: handleCreateEvent
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "cancel-event",
|
|
82
|
+
description: "Cancels a calendar event",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
eventId: {
|
|
87
|
+
type: "string",
|
|
88
|
+
description: "The ID of the event to cancel"
|
|
89
|
+
},
|
|
90
|
+
comment: {
|
|
91
|
+
type: "string",
|
|
92
|
+
description: "Optional comment for cancelling the event"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
required: ["eventId"]
|
|
96
|
+
},
|
|
97
|
+
handler: handleCancelEvent
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: "delete-event",
|
|
101
|
+
description: "Deletes a calendar event",
|
|
102
|
+
inputSchema: {
|
|
103
|
+
type: "object",
|
|
104
|
+
properties: {
|
|
105
|
+
eventId: {
|
|
106
|
+
type: "string",
|
|
107
|
+
description: "The ID of the event to delete"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
required: ["eventId"]
|
|
111
|
+
},
|
|
112
|
+
handler: handleDeleteEvent
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
calendarTools,
|
|
118
|
+
handleListEvents,
|
|
119
|
+
handleDeclineEvent,
|
|
120
|
+
handleCreateEvent,
|
|
121
|
+
handleCancelEvent,
|
|
122
|
+
handleDeleteEvent
|
|
123
|
+
};
|
package/calendar/list.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List events functionality
|
|
3
|
+
*/
|
|
4
|
+
const config = require('../config');
|
|
5
|
+
const { callGraphAPI } = require('../utils/graph-api');
|
|
6
|
+
const { ensureAuthenticated } = require('../auth');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* List events handler
|
|
10
|
+
* @param {object} args - Tool arguments
|
|
11
|
+
* @returns {object} - MCP response
|
|
12
|
+
*/
|
|
13
|
+
async function handleListEvents(args) {
|
|
14
|
+
const count = Math.min(args.count || 10, config.MAX_RESULT_COUNT);
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// Get access token
|
|
18
|
+
const accessToken = await ensureAuthenticated();
|
|
19
|
+
|
|
20
|
+
// Build API endpoint
|
|
21
|
+
let endpoint = 'me/events';
|
|
22
|
+
|
|
23
|
+
// Add query parameters
|
|
24
|
+
const queryParams = {
|
|
25
|
+
$top: count,
|
|
26
|
+
$orderby: 'start/dateTime',
|
|
27
|
+
$filter: `start/dateTime ge '${new Date().toISOString()}'`,
|
|
28
|
+
$select: config.CALENDAR_SELECT_FIELDS
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Make API call
|
|
32
|
+
const response = await callGraphAPI(accessToken, 'GET', endpoint, null, queryParams);
|
|
33
|
+
|
|
34
|
+
if (!response.value || response.value.length === 0) {
|
|
35
|
+
return {
|
|
36
|
+
content: [{
|
|
37
|
+
type: "text",
|
|
38
|
+
text: "No calendar events found."
|
|
39
|
+
}]
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Format results
|
|
44
|
+
const eventList = response.value.map((event, index) => {
|
|
45
|
+
const startDate = new Date(event.start.dateTime).toLocaleString(event.start.timeZone);
|
|
46
|
+
const endDate = new Date(event.end.dateTime).toLocaleString(event.end.timeZone);
|
|
47
|
+
const location = event.location.displayName || 'No location';
|
|
48
|
+
|
|
49
|
+
return `${index + 1}. ${event.subject} - Location: ${location}\nStart: ${startDate}\nEnd: ${endDate}\nSubject: ${event.subject}\nSummary: ${event.bodyPreview}\nID: ${event.id}\n`;
|
|
50
|
+
}).join("\n");
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
content: [{
|
|
54
|
+
type: "text",
|
|
55
|
+
text: `Found ${response.value.length} events:\n\n${eventList}`
|
|
56
|
+
}]
|
|
57
|
+
};
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error.message === 'Authentication required') {
|
|
60
|
+
return {
|
|
61
|
+
content: [{
|
|
62
|
+
type: "text",
|
|
63
|
+
text: "Authentication required. Please use the 'authenticate' tool first."
|
|
64
|
+
}]
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
content: [{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: `Error listing events: ${error.message}`
|
|
72
|
+
}]
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = handleListEvents;
|