outlook-mcp/folder/create.js
Seton Carmichael e70840552d feat(outlook-mcp): shared mailbox targeting, discovery, and scopes (v1.1.0)
Add optional mailbox (UPN/SMTP) routing on email/folder/thread tools via
users/{upn}/... and X-AnchorMailbox. New list-mailboxes probes primary,
OUTLOOK_SHARED_MAILBOXES seeds, cache, and candidates. Send supports
mailbox-rooted sendMail and onBehalfOf. MSAL requests Mail.*.Shared;
check-auth-status reports token scp gaps. Docs, env example, tests.
2026-08-24 08:41:05 -04:00

120 lines
3.2 KiB
JavaScript

/**
* Create folder functionality
*/
const { callGraphAPI } = require('../utils/graph-api');
const { ensureAuthenticated } = require('../auth');
const { getFolderIdByName } = require('../email/folder-utils');
const { normalizeMailbox, buildPath, withMailboxHeaders } = require('../utils/mailbox');
/**
* Create folder handler
* @param {object} args - Tool arguments
* @returns {object} - MCP response
*/
async function handleCreateFolder(args) {
const folderName = args.name;
const parentFolder = args.parentFolder || '';
const mb = normalizeMailbox(args.mailbox);
if (!folderName) {
return {
content: [{
type: "text",
text: "Folder name is required."
}]
};
}
try {
const accessToken = await ensureAuthenticated();
const result = await createMailFolder(accessToken, folderName, parentFolder, mb);
return {
content: [{
type: "text",
text: result.message
}]
};
} catch (error) {
if (error.message === 'Authentication required') {
return {
content: [{
type: "text",
text: "Authentication required. Please use the 'authenticate' tool first."
}]
};
}
return {
content: [{
type: "text",
text: `Error creating folder: ${error.message}`
}]
};
}
}
/**
* Create a new mail folder
*/
async function createMailFolder(accessToken, folderName, parentFolderName, mb) {
const opts = { headers: withMailboxHeaders(mb) };
try {
const existingFolder = await getFolderIdByName(accessToken, folderName, mb);
if (existingFolder) {
return {
success: false,
message: `A folder named "${folderName}" already exists${mb.kind === 'user' ? ` in ${mb.smtpOrUpn}` : ''}.`
};
}
let endpoint = buildPath(mb, 'mailFolders');
if (parentFolderName) {
const parentId = await getFolderIdByName(accessToken, parentFolderName, mb);
if (!parentId) {
return {
success: false,
message: `Parent folder "${parentFolderName}" not found. Please specify a valid parent folder or leave it blank to create at the root level.`
};
}
endpoint = buildPath(mb, `mailFolders/${parentId}/childFolders`);
}
const folderData = {
displayName: folderName
};
const response = await callGraphAPI(
accessToken,
'POST',
endpoint,
folderData,
null,
opts
);
if (response && response.id) {
const locationInfo = parentFolderName
? `inside "${parentFolderName}"`
: "at the root level";
const mailboxInfo = mb.kind === 'user' ? ` (mailbox: ${mb.smtpOrUpn})` : '';
return {
success: true,
message: `Successfully created folder "${folderName}" ${locationInfo}${mailboxInfo}.`,
folderId: response.id
};
} else {
return {
success: false,
message: "Failed to create folder. The server didn't return a folder ID."
};
}
} catch (error) {
console.error(`Error creating folder "${folderName}": ${error.message}`);
throw error;
}
}
module.exports = handleCreateFolder;