ms365-mcp-server 1.1.14 → 1.1.16

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/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import path from 'path';
10
10
  import { fileURLToPath } from 'url';
11
11
  import fs from 'fs/promises';
12
12
  import crypto from 'crypto';
13
- import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
13
+ import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, GetPromptRequestSchema } from '@modelcontextprotocol/sdk/types.js';
14
14
  import { logger } from './utils/api.js';
15
15
  import { MS365Operations } from './utils/ms365-operations.js';
16
16
  import { multiUserMS365Auth } from './utils/multi-user-auth.js';
@@ -67,23 +67,28 @@ function parseArgs() {
67
67
  }
68
68
  const server = new Server({
69
69
  name: "ms365-mcp-server",
70
- version: "1.1.14"
70
+ version: "1.1.16"
71
71
  }, {
72
72
  capabilities: {
73
73
  resources: {
74
74
  read: true,
75
- list: true
75
+ list: true,
76
+ templates: true
76
77
  },
77
78
  tools: {
78
79
  list: true,
79
80
  call: true
80
81
  },
81
82
  prompts: {
83
+ list: true,
84
+ get: true
85
+ },
86
+ resourceTemplates: {
82
87
  list: true
83
88
  }
84
89
  }
85
90
  });
86
- logger.log('Server started with version 1.1.14');
91
+ logger.log('Server started with version 1.1.16');
87
92
  // Set up the resource listing request handler
88
93
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
89
94
  logger.log('Received list resources request');
@@ -103,6 +108,20 @@ server.setRequestHandler(ListPromptsRequestSchema, async () => {
103
108
  logger.log('Received list prompts request');
104
109
  return { prompts: [] };
105
110
  });
111
+ /**
112
+ * Handler for getting a specific prompt.
113
+ */
114
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
115
+ logger.log('Received get prompt request: ' + JSON.stringify(request));
116
+ throw new Error("Prompt getting not implemented");
117
+ });
118
+ /**
119
+ * Handler for listing available resource templates.
120
+ */
121
+ server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
122
+ logger.log('Received list resource templates request');
123
+ return { resourceTemplates: [] };
124
+ });
106
125
  /**
107
126
  * List available tools for interacting with Microsoft 365.
108
127
  */
@@ -201,8 +220,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
201
220
  },
202
221
  action: {
203
222
  type: "string",
204
- enum: ["read", "search", "list", "mark", "move", "delete", "search_to_me", "draft", "update_draft", "send_draft", "list_drafts", "reply_draft", "forward_draft"],
205
- description: "Action to perform: read (get email by ID), search (find emails), list (folder contents), mark (read/unread), move (to folder), delete (permanently), search_to_me (emails addressed to you), draft (create standalone draft - NOTE: Use reply_draft/forward_draft for threaded drafts), update_draft (modify existing draft), send_draft (send saved draft), list_drafts (list draft emails), reply_draft (create threaded reply draft that appears in conversation), forward_draft (create threaded forward draft that appears in conversation)"
223
+ enum: ["read", "search", "search_batched", "list", "mark", "move", "delete", "search_to_me", "draft", "update_draft", "send_draft", "list_drafts", "reply_draft", "forward_draft"],
224
+ description: "Action to perform: read (get email by ID), search (find emails), search_batched (find emails in batches of 50, up to 5 batches for better performance), list (folder contents), mark (read/unread), move (to folder), delete (permanently), search_to_me (emails addressed to you), draft (create standalone draft - NOTE: Use reply_draft/forward_draft for threaded drafts), update_draft (modify existing draft), send_draft (send saved draft), list_drafts (list draft emails), reply_draft (create threaded reply draft that appears in conversation), forward_draft (create threaded forward draft that appears in conversation)"
206
225
  },
207
226
  messageId: {
208
227
  type: "string",
@@ -273,11 +292,24 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
273
292
  },
274
293
  maxResults: {
275
294
  type: "number",
276
- description: "Maximum number of results to return (default: 50, max: 200)",
277
- minimum: 1,
278
- maximum: 200,
295
+ description: "Maximum number of results to return. Set to 0 or omit to get ALL matching results (safety limited to 1000). For large result sets, use specific maxResults values to avoid timeouts. Default: 50",
296
+ minimum: 0,
279
297
  default: 50
280
298
  },
299
+ batchSize: {
300
+ type: "number",
301
+ description: "Number of results per batch for search_batched action (default: 50)",
302
+ minimum: 10,
303
+ maximum: 100,
304
+ default: 50
305
+ },
306
+ maxBatches: {
307
+ type: "number",
308
+ description: "Maximum number of batches for search_batched action (default: 5)",
309
+ minimum: 1,
310
+ maximum: 10,
311
+ default: 5
312
+ },
281
313
  // Draft email parameters
282
314
  draftTo: {
283
315
  oneOf: [
@@ -726,6 +758,52 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
726
758
  }
727
759
  ]
728
760
  };
761
+ case "search_batched":
762
+ const batchSize = args?.batchSize || 50;
763
+ const maxBatches = args?.maxBatches || 5;
764
+ logger.log(`DEBUG: Starting batched search with batchSize: ${batchSize}, maxBatches: ${maxBatches}`);
765
+ const batchedSearchResults = await ms365Ops.searchEmailsBatched(args, batchSize, maxBatches);
766
+ logger.log(`DEBUG: Batched search results count: ${batchedSearchResults.messages.length} from ${batchedSearchResults.totalBatches} batches`);
767
+ // Enhanced feedback for batched search results
768
+ let batchedResponseText = `šŸ” Batched Email Search Results (${batchedSearchResults.messages.length} found from ${batchedSearchResults.totalBatches} batches)`;
769
+ if (batchedSearchResults.messages.length === 0) {
770
+ batchedResponseText = `šŸ” No emails found matching your criteria.\n\nšŸ’” Search Tips:\n`;
771
+ if (args?.from) {
772
+ batchedResponseText += `• Try partial names: "${args.from.split(' ')[0]}" or "${args.from.split(' ').pop()}"\n`;
773
+ batchedResponseText += `• Check spelling of sender name\n`;
774
+ }
775
+ if (args?.subject) {
776
+ batchedResponseText += `• Try broader subject terms\n`;
777
+ }
778
+ if (args?.after || args?.before) {
779
+ batchedResponseText += `• Try expanding date range\n`;
780
+ }
781
+ batchedResponseText += `• Remove some search criteria to get broader results`;
782
+ }
783
+ else {
784
+ batchedResponseText += `\n\n${batchedSearchResults.messages.map((email, index) => {
785
+ // Handle missing IDs more gracefully
786
+ const emailId = email.id || 'ID_MISSING';
787
+ const fromDisplay = email.from?.name ? `${email.from.name} <${email.from.address}>` : email.from?.address || 'Unknown sender';
788
+ return `${index + 1}. šŸ“§ ${email.subject || 'No subject'}\n šŸ‘¤ From: ${fromDisplay}\n šŸ“… ${email.receivedDateTime ? new Date(email.receivedDateTime).toLocaleDateString() : 'Unknown date'}\n ${email.isRead ? 'šŸ“– Read' : 'šŸ“© Unread'}\n šŸ†” ID: ${emailId}\n`;
789
+ }).join('\n')}`;
790
+ if (batchedSearchResults.hasMore) {
791
+ batchedResponseText += `\nšŸ’” There are more results available. Increase maxBatches parameter to get more emails.`;
792
+ }
793
+ batchedResponseText += `\n\nšŸ“Š Search Summary:\n`;
794
+ batchedResponseText += `• Total results: ${batchedSearchResults.messages.length}\n`;
795
+ batchedResponseText += `• Batches processed: ${batchedSearchResults.totalBatches}/${maxBatches}\n`;
796
+ batchedResponseText += `• Batch size: ${batchSize}\n`;
797
+ batchedResponseText += `• More results available: ${batchedSearchResults.hasMore ? 'Yes' : 'No'}`;
798
+ }
799
+ return {
800
+ content: [
801
+ {
802
+ type: "text",
803
+ text: batchedResponseText
804
+ }
805
+ ]
806
+ };
729
807
  case "search_to_me":
730
808
  const searchToMeResults = await ms365Ops.searchEmailsToMe(args);
731
809
  // Process attachments for each email