@leonardocrdso/office365-mcp-server 1.0.4 → 1.1.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/build/index.js +236 -83
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -23555,6 +23555,64 @@ class StdioServerTransport {
|
|
|
23555
23555
|
});
|
|
23556
23556
|
}
|
|
23557
23557
|
}
|
|
23558
|
+
// package.json
|
|
23559
|
+
var package_default = {
|
|
23560
|
+
name: "@leonardocrdso/office365-mcp-server",
|
|
23561
|
+
version: "1.1.0",
|
|
23562
|
+
description: "MCP server for Microsoft 365 — Outlook, Calendar, OneDrive, SharePoint & Teams via Graph API",
|
|
23563
|
+
type: "module",
|
|
23564
|
+
main: "build/index.js",
|
|
23565
|
+
bin: {
|
|
23566
|
+
"office365-mcp-server": "build/index.js"
|
|
23567
|
+
},
|
|
23568
|
+
files: [
|
|
23569
|
+
"build/",
|
|
23570
|
+
"README.md",
|
|
23571
|
+
"LICENSE"
|
|
23572
|
+
],
|
|
23573
|
+
scripts: {
|
|
23574
|
+
dev: "bun run --watch src/index.ts",
|
|
23575
|
+
start: "bun run src/index.ts",
|
|
23576
|
+
build: "bun build src/index.ts --outdir build --target node",
|
|
23577
|
+
prepublishOnly: "bun run build"
|
|
23578
|
+
},
|
|
23579
|
+
keywords: [
|
|
23580
|
+
"office365",
|
|
23581
|
+
"microsoft-365",
|
|
23582
|
+
"outlook",
|
|
23583
|
+
"teams",
|
|
23584
|
+
"onedrive",
|
|
23585
|
+
"sharepoint",
|
|
23586
|
+
"calendar",
|
|
23587
|
+
"mcp",
|
|
23588
|
+
"model-context-protocol",
|
|
23589
|
+
"microsoft-graph",
|
|
23590
|
+
"claude",
|
|
23591
|
+
"ai"
|
|
23592
|
+
],
|
|
23593
|
+
author: "leonardocrdso",
|
|
23594
|
+
license: "MIT",
|
|
23595
|
+
repository: {
|
|
23596
|
+
type: "git",
|
|
23597
|
+
url: "git+https://github.com/leonardocrdso/office365-mcp-server.git"
|
|
23598
|
+
},
|
|
23599
|
+
homepage: "https://github.com/leonardocrdso/office365-mcp-server#readme",
|
|
23600
|
+
bugs: {
|
|
23601
|
+
url: "https://github.com/leonardocrdso/office365-mcp-server/issues"
|
|
23602
|
+
},
|
|
23603
|
+
publishConfig: {
|
|
23604
|
+
access: "public"
|
|
23605
|
+
},
|
|
23606
|
+
dependencies: {
|
|
23607
|
+
"@azure/msal-node": "^3.8.8",
|
|
23608
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
23609
|
+
zod: "^3.25.0"
|
|
23610
|
+
},
|
|
23611
|
+
devDependencies: {
|
|
23612
|
+
"@types/node": "^22.0.0",
|
|
23613
|
+
typescript: "^5.0.0"
|
|
23614
|
+
}
|
|
23615
|
+
};
|
|
23558
23616
|
|
|
23559
23617
|
// node_modules/@azure/msal-node/dist/cache/serializer/Serializer.mjs
|
|
23560
23618
|
/*! @azure/msal-node v3.8.8 2026-02-23 */
|
|
@@ -31708,16 +31766,12 @@ var SOURCES_THAT_SUPPORT_TOKEN_REVOCATION = [ManagedIdentitySourceNames.SERVICE_
|
|
|
31708
31766
|
// node_modules/@azure/msal-node/dist/index.mjs
|
|
31709
31767
|
/*! @azure/msal-node v3.8.8 2026-02-23 */
|
|
31710
31768
|
|
|
31711
|
-
// src/auth/msal-client.ts
|
|
31712
|
-
import { readFile, writeFile, unlink } from "node:fs/promises";
|
|
31713
|
-
import { homedir } from "node:os";
|
|
31714
|
-
import { join } from "node:path";
|
|
31715
|
-
|
|
31716
31769
|
// src/constants.ts
|
|
31717
31770
|
var DEFAULT_PAGE_SIZE_SMALL = 10;
|
|
31718
31771
|
var DEFAULT_PAGE_SIZE_LARGE = 20;
|
|
31719
31772
|
var DEFAULT_MEETING_DURATION_MINUTES = 30;
|
|
31720
31773
|
var DEFAULT_TIMEZONE = "America/Sao_Paulo";
|
|
31774
|
+
var PREFER_TIMEZONE_HEADER = `outlook.timezone="${DEFAULT_TIMEZONE}"`;
|
|
31721
31775
|
var BODY_PREVIEW_MAX_LENGTH = 100;
|
|
31722
31776
|
var MESSAGE_CONTENT_MAX_LENGTH = 200;
|
|
31723
31777
|
var SCOPES = {
|
|
@@ -31833,7 +31887,7 @@ var GRAPH_CODE_MAP = {
|
|
|
31833
31887
|
ErrorSendAsDenied: ErrorCode2.PERMISSION_DENIED
|
|
31834
31888
|
};
|
|
31835
31889
|
var ERROR_MESSAGES = {
|
|
31836
|
-
[ErrorCode2.AUTH_NOT_CONFIGURED]: "AZURE_CLIENT_ID não configurado.
|
|
31890
|
+
[ErrorCode2.AUTH_NOT_CONFIGURED]: "AZURE_CLIENT_ID não configurado. Use a tool 'configure' para informar suas credenciais Azure, ou defina a variável de ambiente AZURE_CLIENT_ID.",
|
|
31837
31891
|
[ErrorCode2.AUTH_NOT_AUTHENTICATED]: "Usuário não autenticado. Use a tool 'login' para iniciar a autenticação.",
|
|
31838
31892
|
[ErrorCode2.AUTH_TOKEN_EXPIRED]: "Token expirado ou inválido. Use a tool 'login' para re-autenticar.",
|
|
31839
31893
|
[ErrorCode2.AUTH_TOKEN_REFRESH_FAILED]: "Falha ao renovar token silenciosamente. Use a tool 'login' para re-autenticar.",
|
|
@@ -31877,23 +31931,65 @@ Detalhe: ${error2.message}`;
|
|
|
31877
31931
|
return `[${ErrorCode2.UNKNOWN_ERROR}] ${String(error2)}`;
|
|
31878
31932
|
}
|
|
31879
31933
|
|
|
31934
|
+
// src/auth/config-manager.ts
|
|
31935
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
31936
|
+
import { homedir } from "node:os";
|
|
31937
|
+
import { join } from "node:path";
|
|
31938
|
+
var CONFIG_PATH = join(homedir(), ".office365-mcp-config.json");
|
|
31939
|
+
async function loadConfig() {
|
|
31940
|
+
try {
|
|
31941
|
+
const data = await readFile(CONFIG_PATH, "utf-8");
|
|
31942
|
+
return JSON.parse(data);
|
|
31943
|
+
} catch {
|
|
31944
|
+
return {};
|
|
31945
|
+
}
|
|
31946
|
+
}
|
|
31947
|
+
async function saveConfig(clientId, tenantId) {
|
|
31948
|
+
await writeFile(CONFIG_PATH, JSON.stringify({ clientId, tenantId }, null, 2), { mode: 384 });
|
|
31949
|
+
}
|
|
31950
|
+
|
|
31951
|
+
// src/auth/token-cache-manager.ts
|
|
31952
|
+
import { readFile as readFile2, writeFile as writeFile2, unlink } from "node:fs/promises";
|
|
31953
|
+
import { homedir as homedir2 } from "node:os";
|
|
31954
|
+
import { join as join2 } from "node:path";
|
|
31955
|
+
var TOKEN_CACHE_PATH = join2(homedir2(), ".office365-mcp-tokens.json");
|
|
31956
|
+
async function loadTokenCache() {
|
|
31957
|
+
try {
|
|
31958
|
+
return await readFile2(TOKEN_CACHE_PATH, "utf-8");
|
|
31959
|
+
} catch {
|
|
31960
|
+
return null;
|
|
31961
|
+
}
|
|
31962
|
+
}
|
|
31963
|
+
async function saveTokenCache(data) {
|
|
31964
|
+
await writeFile2(TOKEN_CACHE_PATH, data, { mode: 384 });
|
|
31965
|
+
}
|
|
31966
|
+
async function removeTokenCache() {
|
|
31967
|
+
try {
|
|
31968
|
+
await unlink(TOKEN_CACHE_PATH);
|
|
31969
|
+
} catch {}
|
|
31970
|
+
}
|
|
31971
|
+
|
|
31880
31972
|
// src/auth/msal-client.ts
|
|
31881
|
-
var TOKEN_CACHE_PATH = join(homedir(), ".office365-mcp-tokens.json");
|
|
31882
31973
|
var ALL_SCOPES = ["User.Read", ...Object.values(SCOPES).flat()];
|
|
31883
31974
|
|
|
31884
31975
|
class MsalClient {
|
|
31885
31976
|
pca = null;
|
|
31977
|
+
fileConfig = null;
|
|
31886
31978
|
deviceCodeCallback = null;
|
|
31887
31979
|
pendingLogin = null;
|
|
31888
31980
|
setDeviceCodeCallback(callback) {
|
|
31889
31981
|
this.deviceCodeCallback = callback;
|
|
31890
31982
|
}
|
|
31983
|
+
resetPca() {
|
|
31984
|
+
this.pca = null;
|
|
31985
|
+
this.fileConfig = null;
|
|
31986
|
+
}
|
|
31891
31987
|
getConfig() {
|
|
31892
|
-
const clientId = process.env.AZURE_CLIENT_ID;
|
|
31988
|
+
const clientId = process.env.AZURE_CLIENT_ID ?? this.fileConfig?.clientId;
|
|
31893
31989
|
if (!clientId) {
|
|
31894
31990
|
throw new AuthError2("AZURE_CLIENT_ID não configurado.", ErrorCode2.AUTH_NOT_CONFIGURED);
|
|
31895
31991
|
}
|
|
31896
|
-
const tenantId = process.env.AZURE_TENANT_ID
|
|
31992
|
+
const tenantId = process.env.AZURE_TENANT_ID ?? this.fileConfig?.tenantId ?? "common";
|
|
31897
31993
|
return {
|
|
31898
31994
|
auth: {
|
|
31899
31995
|
clientId,
|
|
@@ -31903,10 +31999,15 @@ class MsalClient {
|
|
|
31903
31999
|
}
|
|
31904
32000
|
async getPca() {
|
|
31905
32001
|
if (!this.pca) {
|
|
32002
|
+
if (!this.fileConfig) {
|
|
32003
|
+
this.fileConfig = await loadConfig();
|
|
32004
|
+
}
|
|
31906
32005
|
this.pca = new PublicClientApplication(this.getConfig());
|
|
31907
32006
|
try {
|
|
31908
|
-
const cacheData = await
|
|
31909
|
-
|
|
32007
|
+
const cacheData = await loadTokenCache();
|
|
32008
|
+
if (cacheData) {
|
|
32009
|
+
this.pca.getTokenCache().deserialize(cacheData);
|
|
32010
|
+
}
|
|
31910
32011
|
} catch (error2) {
|
|
31911
32012
|
console.error("Failed to load token cache:", error2);
|
|
31912
32013
|
}
|
|
@@ -31917,7 +32018,7 @@ class MsalClient {
|
|
|
31917
32018
|
if (!this.pca)
|
|
31918
32019
|
return;
|
|
31919
32020
|
const cacheData = this.pca.getTokenCache().serialize();
|
|
31920
|
-
await
|
|
32021
|
+
await saveTokenCache(cacheData);
|
|
31921
32022
|
}
|
|
31922
32023
|
async login() {
|
|
31923
32024
|
const pca = await this.getPca();
|
|
@@ -31990,16 +32091,29 @@ class MsalClient {
|
|
|
31990
32091
|
await this.pca.getTokenCache().removeAccount(account);
|
|
31991
32092
|
}
|
|
31992
32093
|
}
|
|
31993
|
-
|
|
31994
|
-
await unlink(TOKEN_CACHE_PATH);
|
|
31995
|
-
} catch (error2) {
|
|
31996
|
-
console.error("Failed to remove token cache file:", error2);
|
|
31997
|
-
}
|
|
32094
|
+
await removeTokenCache();
|
|
31998
32095
|
this.pca = null;
|
|
31999
32096
|
}
|
|
32000
32097
|
}
|
|
32001
32098
|
var msalClient = new MsalClient;
|
|
32002
32099
|
|
|
32100
|
+
// src/types/graph.ts
|
|
32101
|
+
function recipientAddress(recipient) {
|
|
32102
|
+
return recipient?.emailAddress?.address ?? "unknown";
|
|
32103
|
+
}
|
|
32104
|
+
function recipientAddresses(recipients) {
|
|
32105
|
+
return recipients?.map((r) => r.emailAddress?.address).join(", ") ?? "";
|
|
32106
|
+
}
|
|
32107
|
+
function messageSenderName(message) {
|
|
32108
|
+
return message.from?.user?.displayName ?? "Desconhecido";
|
|
32109
|
+
}
|
|
32110
|
+
function toRecipient(email2) {
|
|
32111
|
+
return { emailAddress: { address: email2 } };
|
|
32112
|
+
}
|
|
32113
|
+
function toAttendee(email2, type = "required") {
|
|
32114
|
+
return { emailAddress: { address: email2 }, type };
|
|
32115
|
+
}
|
|
32116
|
+
|
|
32003
32117
|
// src/utils/graph-client.ts
|
|
32004
32118
|
async function executeRequest(accessToken, url, options = {}) {
|
|
32005
32119
|
const baseUrl = url.startsWith("https://") ? url : `https://graph.microsoft.com/v1.0${url}`;
|
|
@@ -32042,11 +32156,14 @@ async function graphFetchVoid(accessToken, url, options = {}) {
|
|
|
32042
32156
|
await executeRequest(accessToken, url, options);
|
|
32043
32157
|
}
|
|
32044
32158
|
|
|
32159
|
+
// src/utils/auth-helper.ts
|
|
32160
|
+
function createGetToken(auth, scopes) {
|
|
32161
|
+
return () => auth.getAccessToken([...scopes]);
|
|
32162
|
+
}
|
|
32163
|
+
|
|
32045
32164
|
// src/services/mail.ts
|
|
32046
32165
|
function createMailService(auth) {
|
|
32047
|
-
|
|
32048
|
-
return auth.getAccessToken([...SCOPES.MAIL]);
|
|
32049
|
-
}
|
|
32166
|
+
const getToken = createGetToken(auth, SCOPES.MAIL);
|
|
32050
32167
|
async function listEmails(params = {}) {
|
|
32051
32168
|
const token = await getToken();
|
|
32052
32169
|
const { folder, top = DEFAULT_PAGE_SIZE_SMALL, skip = 0, filter } = params;
|
|
@@ -32079,15 +32196,9 @@ function createMailService(auth) {
|
|
|
32079
32196
|
async function sendEmail(params) {
|
|
32080
32197
|
const token = await getToken();
|
|
32081
32198
|
const { to, subject, body, cc, bcc, contentType = "Text" } = params;
|
|
32082
|
-
const toRecipients = to.map(
|
|
32083
|
-
|
|
32084
|
-
|
|
32085
|
-
const ccRecipients = cc?.map((email2) => ({
|
|
32086
|
-
emailAddress: { address: email2 }
|
|
32087
|
-
}));
|
|
32088
|
-
const bccRecipients = bcc?.map((email2) => ({
|
|
32089
|
-
emailAddress: { address: email2 }
|
|
32090
|
-
}));
|
|
32199
|
+
const toRecipients = to.map(toRecipient);
|
|
32200
|
+
const ccRecipients = cc?.map(toRecipient);
|
|
32201
|
+
const bccRecipients = bcc?.map(toRecipient);
|
|
32091
32202
|
await graphFetchVoid(token, "/me/sendMail", {
|
|
32092
32203
|
method: "POST",
|
|
32093
32204
|
body: JSON.stringify({
|
|
@@ -32123,9 +32234,7 @@ function createMailService(auth) {
|
|
|
32123
32234
|
|
|
32124
32235
|
// src/services/calendar.ts
|
|
32125
32236
|
function createCalendarService(auth) {
|
|
32126
|
-
|
|
32127
|
-
return auth.getAccessToken([...SCOPES.CALENDAR]);
|
|
32128
|
-
}
|
|
32237
|
+
const getToken = createGetToken(auth, SCOPES.CALENDAR);
|
|
32129
32238
|
async function listEvents(params) {
|
|
32130
32239
|
const token = await getToken();
|
|
32131
32240
|
const { startDateTime, endDateTime, top = DEFAULT_PAGE_SIZE_LARGE } = params;
|
|
@@ -32136,7 +32245,11 @@ function createCalendarService(auth) {
|
|
|
32136
32245
|
$select: "id,subject,start,end,location,organizer,attendees,isOnlineMeeting,onlineMeetingUrl,bodyPreview",
|
|
32137
32246
|
$orderby: "start/dateTime"
|
|
32138
32247
|
});
|
|
32139
|
-
const result = await graphFetch(token, `/me/calendarView?${queryParams}
|
|
32248
|
+
const result = await graphFetch(token, `/me/calendarView?${queryParams}`, {
|
|
32249
|
+
headers: {
|
|
32250
|
+
Prefer: PREFER_TIMEZONE_HEADER
|
|
32251
|
+
}
|
|
32252
|
+
});
|
|
32140
32253
|
return result.value;
|
|
32141
32254
|
}
|
|
32142
32255
|
async function createEvent(params) {
|
|
@@ -32164,10 +32277,7 @@ function createCalendarService(auth) {
|
|
|
32164
32277
|
eventBody.location = { displayName: location };
|
|
32165
32278
|
}
|
|
32166
32279
|
if (attendees?.length) {
|
|
32167
|
-
eventBody.attendees = attendees.map((email2) => (
|
|
32168
|
-
emailAddress: { address: email2 },
|
|
32169
|
-
type: "required"
|
|
32170
|
-
}));
|
|
32280
|
+
eventBody.attendees = attendees.map((email2) => toAttendee(email2));
|
|
32171
32281
|
}
|
|
32172
32282
|
return graphFetch(token, "/me/events", {
|
|
32173
32283
|
method: "POST",
|
|
@@ -32208,11 +32318,11 @@ function createCalendarService(auth) {
|
|
|
32208
32318
|
} = params;
|
|
32209
32319
|
return graphFetch(token, "/me/findMeetingTimes", {
|
|
32210
32320
|
method: "POST",
|
|
32321
|
+
headers: {
|
|
32322
|
+
Prefer: PREFER_TIMEZONE_HEADER
|
|
32323
|
+
},
|
|
32211
32324
|
body: JSON.stringify({
|
|
32212
|
-
attendees: attendees.map((email2) => (
|
|
32213
|
-
emailAddress: { address: email2 },
|
|
32214
|
-
type: "required"
|
|
32215
|
-
})),
|
|
32325
|
+
attendees: attendees.map((email2) => toAttendee(email2)),
|
|
32216
32326
|
timeConstraint: {
|
|
32217
32327
|
timeslots: [
|
|
32218
32328
|
{
|
|
@@ -32230,9 +32340,7 @@ function createCalendarService(auth) {
|
|
|
32230
32340
|
|
|
32231
32341
|
// src/services/onedrive.ts
|
|
32232
32342
|
function createOneDriveService(auth) {
|
|
32233
|
-
|
|
32234
|
-
return auth.getAccessToken([...SCOPES.DRIVE]);
|
|
32235
|
-
}
|
|
32343
|
+
const getToken = createGetToken(auth, SCOPES.DRIVE);
|
|
32236
32344
|
async function listFiles(params = {}) {
|
|
32237
32345
|
const token = await getToken();
|
|
32238
32346
|
const { itemId, path, top = DEFAULT_PAGE_SIZE_LARGE } = params;
|
|
@@ -32255,6 +32363,19 @@ function createOneDriveService(auth) {
|
|
|
32255
32363
|
const token = await getToken();
|
|
32256
32364
|
return graphFetch(token, `/me/drive/items/${itemId}/content`);
|
|
32257
32365
|
}
|
|
32366
|
+
async function readSharedFileContent(params) {
|
|
32367
|
+
const token = await getToken();
|
|
32368
|
+
const { driveId, itemId, path } = params;
|
|
32369
|
+
let endpoint;
|
|
32370
|
+
if (itemId) {
|
|
32371
|
+
endpoint = `/drives/${driveId}/items/${itemId}/content`;
|
|
32372
|
+
} else if (path) {
|
|
32373
|
+
endpoint = `/drives/${driveId}/root:/${path.replace(/^\//, "")}:/content`;
|
|
32374
|
+
} else {
|
|
32375
|
+
throw new Error("É necessário informar itemId ou path do arquivo.");
|
|
32376
|
+
}
|
|
32377
|
+
return graphFetch(token, endpoint);
|
|
32378
|
+
}
|
|
32258
32379
|
async function uploadFile(params) {
|
|
32259
32380
|
const token = await getToken();
|
|
32260
32381
|
const { path, content } = params;
|
|
@@ -32282,14 +32403,12 @@ function createOneDriveService(auth) {
|
|
|
32282
32403
|
body: JSON.stringify({ type, scope })
|
|
32283
32404
|
});
|
|
32284
32405
|
}
|
|
32285
|
-
return { listFiles, readFileContent, uploadFile, searchFiles, shareFile };
|
|
32406
|
+
return { listFiles, readFileContent, readSharedFileContent, uploadFile, searchFiles, shareFile };
|
|
32286
32407
|
}
|
|
32287
32408
|
|
|
32288
32409
|
// src/services/sharepoint.ts
|
|
32289
32410
|
function createSharePointService(auth) {
|
|
32290
|
-
|
|
32291
|
-
return auth.getAccessToken([...SCOPES.SHAREPOINT]);
|
|
32292
|
-
}
|
|
32411
|
+
const getToken = createGetToken(auth, SCOPES.SHAREPOINT);
|
|
32293
32412
|
async function listSites(query) {
|
|
32294
32413
|
const token = await getToken();
|
|
32295
32414
|
const searchQuery = query ?? "*";
|
|
@@ -32338,9 +32457,7 @@ function createSharePointService(auth) {
|
|
|
32338
32457
|
|
|
32339
32458
|
// src/services/teams.ts
|
|
32340
32459
|
function createTeamsService(auth) {
|
|
32341
|
-
|
|
32342
|
-
return auth.getAccessToken([...SCOPES.TEAMS]);
|
|
32343
|
-
}
|
|
32460
|
+
const getToken = createGetToken(auth, SCOPES.TEAMS);
|
|
32344
32461
|
async function listTeams() {
|
|
32345
32462
|
const token = await getToken();
|
|
32346
32463
|
const result = await graphFetch(token, "/me/joinedTeams?$select=id,displayName,description");
|
|
@@ -32408,9 +32525,33 @@ function safeTool(handler) {
|
|
|
32408
32525
|
}
|
|
32409
32526
|
|
|
32410
32527
|
// src/tools/auth-tools.ts
|
|
32411
|
-
function registerAuthTools(server) {
|
|
32528
|
+
function registerAuthTools(server, auth) {
|
|
32529
|
+
server.tool("configure", "Configura as credenciais do Azure (Client ID e Tenant ID) para autenticação com Microsoft 365. Salva em arquivo persistente (~/.office365-mcp-config.json).", {
|
|
32530
|
+
clientId: exports_external.string().describe("Azure App Registration Client ID"),
|
|
32531
|
+
tenantId: exports_external.string().optional().default("common").describe("Azure Tenant ID (padrão: 'common')")
|
|
32532
|
+
}, safeTool(async (params) => {
|
|
32533
|
+
await saveConfig(params.clientId, params.tenantId);
|
|
32534
|
+
auth.resetPca();
|
|
32535
|
+
return {
|
|
32536
|
+
content: [
|
|
32537
|
+
{
|
|
32538
|
+
type: "text",
|
|
32539
|
+
text: [
|
|
32540
|
+
"## Configuração salva com sucesso",
|
|
32541
|
+
"",
|
|
32542
|
+
`**Client ID:** \`${params.clientId}\``,
|
|
32543
|
+
`**Tenant ID:** \`${params.tenantId}\``,
|
|
32544
|
+
"",
|
|
32545
|
+
"As credenciais foram salvas em `~/.office365-mcp-config.json`.",
|
|
32546
|
+
"Agora use a tool **'login'** para autenticar com sua conta Microsoft."
|
|
32547
|
+
].join(`
|
|
32548
|
+
`)
|
|
32549
|
+
}
|
|
32550
|
+
]
|
|
32551
|
+
};
|
|
32552
|
+
}));
|
|
32412
32553
|
server.tool("login", "Inicia autenticação com Microsoft 365 via Device Code Flow. Retorna um código e URL para o usuário autenticar no navegador.", {}, safeTool(async () => {
|
|
32413
|
-
const result = await
|
|
32554
|
+
const result = await auth.login();
|
|
32414
32555
|
return {
|
|
32415
32556
|
content: [
|
|
32416
32557
|
{
|
|
@@ -32432,7 +32573,7 @@ function registerAuthTools(server) {
|
|
|
32432
32573
|
};
|
|
32433
32574
|
}));
|
|
32434
32575
|
server.tool("auth-status", "Verifica o status da autenticação e mostra informações do usuário logado.", {}, safeTool(async () => {
|
|
32435
|
-
const info = await
|
|
32576
|
+
const info = await auth.getAccountInfo();
|
|
32436
32577
|
if (!info.isLoggedIn) {
|
|
32437
32578
|
return {
|
|
32438
32579
|
content: [
|
|
@@ -32461,7 +32602,7 @@ function registerAuthTools(server) {
|
|
|
32461
32602
|
};
|
|
32462
32603
|
}));
|
|
32463
32604
|
server.tool("logout", "Faz logout e remove tokens salvos.", {}, safeTool(async () => {
|
|
32464
|
-
await
|
|
32605
|
+
await auth.logout();
|
|
32465
32606
|
return {
|
|
32466
32607
|
content: [
|
|
32467
32608
|
{
|
|
@@ -32473,15 +32614,17 @@ function registerAuthTools(server) {
|
|
|
32473
32614
|
}));
|
|
32474
32615
|
}
|
|
32475
32616
|
|
|
32476
|
-
// src/
|
|
32477
|
-
function
|
|
32478
|
-
return
|
|
32479
|
-
}
|
|
32480
|
-
function recipientAddresses(recipients) {
|
|
32481
|
-
return recipients?.map((r) => r.emailAddress?.address).join(", ") ?? "";
|
|
32617
|
+
// src/utils/date.ts
|
|
32618
|
+
function formatDateBR(isoDate) {
|
|
32619
|
+
return new Date(isoDate).toLocaleString("pt-BR", { timeZone: DEFAULT_TIMEZONE });
|
|
32482
32620
|
}
|
|
32483
|
-
function
|
|
32484
|
-
|
|
32621
|
+
function formatCalendarDate(dateTime) {
|
|
32622
|
+
const match = dateTime.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})/);
|
|
32623
|
+
if (match) {
|
|
32624
|
+
const [, year, month, day, hour, minute] = match;
|
|
32625
|
+
return `${day}/${month}/${year}, ${hour}:${minute}`;
|
|
32626
|
+
}
|
|
32627
|
+
return new Date(dateTime).toLocaleString("pt-BR", { timeZone: DEFAULT_TIMEZONE });
|
|
32485
32628
|
}
|
|
32486
32629
|
|
|
32487
32630
|
// src/formatters/mail.ts
|
|
@@ -32490,7 +32633,7 @@ function formatEmailList(emails) {
|
|
|
32490
32633
|
return "Nenhum email encontrado.";
|
|
32491
32634
|
const formatted = emails.map((e) => {
|
|
32492
32635
|
const from = recipientAddress(e.from);
|
|
32493
|
-
const date4 =
|
|
32636
|
+
const date4 = formatDateBR(e.receivedDateTime);
|
|
32494
32637
|
const read = e.isRead ? "" : " [NÃO LIDO]";
|
|
32495
32638
|
const attach = e.hasAttachments ? " [ANEXO]" : "";
|
|
32496
32639
|
return `- **${e.subject}**${read}${attach}
|
|
@@ -32509,7 +32652,7 @@ function formatEmailSearchResults(query, emails) {
|
|
|
32509
32652
|
return `Nenhum email encontrado para "${query}".`;
|
|
32510
32653
|
const formatted = emails.map((e) => {
|
|
32511
32654
|
const from = recipientAddress(e.from);
|
|
32512
|
-
const date4 =
|
|
32655
|
+
const date4 = formatDateBR(e.receivedDateTime);
|
|
32513
32656
|
return `- **${e.subject}**
|
|
32514
32657
|
De: ${from} | ${date4}
|
|
32515
32658
|
ID: ${e.id}`;
|
|
@@ -32524,7 +32667,7 @@ function formatEmailDetail(email2) {
|
|
|
32524
32667
|
const from = recipientAddress(email2.from);
|
|
32525
32668
|
const to = recipientAddresses(email2.toRecipients);
|
|
32526
32669
|
const cc = recipientAddresses(email2.ccRecipients);
|
|
32527
|
-
const date4 =
|
|
32670
|
+
const date4 = formatDateBR(email2.receivedDateTime);
|
|
32528
32671
|
const bodyContent = email2.body?.content ?? "(sem conteúdo)";
|
|
32529
32672
|
const text = [
|
|
32530
32673
|
`## ${email2.subject}`,
|
|
@@ -32629,8 +32772,8 @@ function formatEventList(events) {
|
|
|
32629
32772
|
if (events.length === 0)
|
|
32630
32773
|
return "Nenhum evento encontrado no período.";
|
|
32631
32774
|
const formatted = events.map((e) => {
|
|
32632
|
-
const start =
|
|
32633
|
-
const end =
|
|
32775
|
+
const start = formatCalendarDate(e.start.dateTime);
|
|
32776
|
+
const end = formatCalendarDate(e.end.dateTime);
|
|
32634
32777
|
const location = e.location?.displayName ? ` @ ${e.location.displayName}` : "";
|
|
32635
32778
|
const online = e.isOnlineMeeting ? " [Online]" : "";
|
|
32636
32779
|
const attendees = e.attendees?.length ? `
|
|
@@ -32662,8 +32805,8 @@ function formatFreeSlotsResult(result) {
|
|
|
32662
32805
|
return "Nenhum horário disponível encontrado para todos os participantes no período.";
|
|
32663
32806
|
}
|
|
32664
32807
|
const formatted = suggestions.map((s, i) => {
|
|
32665
|
-
const start =
|
|
32666
|
-
const end =
|
|
32808
|
+
const start = formatCalendarDate(s.meetingTimeSlot.start.dateTime);
|
|
32809
|
+
const end = formatCalendarDate(s.meetingTimeSlot.end.dateTime);
|
|
32667
32810
|
return `${i + 1}. ${start} → ${end} (confiança: ${s.confidence}%)`;
|
|
32668
32811
|
});
|
|
32669
32812
|
return `## Horários Sugeridos
|
|
@@ -32741,7 +32884,7 @@ function registerCalendarTools(server, calendar) {
|
|
|
32741
32884
|
}));
|
|
32742
32885
|
}
|
|
32743
32886
|
|
|
32744
|
-
// src/
|
|
32887
|
+
// src/utils/format.ts
|
|
32745
32888
|
function formatSize(bytes) {
|
|
32746
32889
|
if (bytes < 1024)
|
|
32747
32890
|
return `${bytes} B`;
|
|
@@ -32751,6 +32894,8 @@ function formatSize(bytes) {
|
|
|
32751
32894
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
32752
32895
|
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
32753
32896
|
}
|
|
32897
|
+
|
|
32898
|
+
// src/formatters/onedrive.ts
|
|
32754
32899
|
function formatDriveItems(items) {
|
|
32755
32900
|
if (items.length === 0)
|
|
32756
32901
|
return "Pasta vazia.";
|
|
@@ -32758,7 +32903,7 @@ function formatDriveItems(items) {
|
|
|
32758
32903
|
const isFolder = !!item.folder;
|
|
32759
32904
|
const icon = isFolder ? "[pasta]" : "[arquivo]";
|
|
32760
32905
|
const size = item.size ? ` (${formatSize(item.size)})` : "";
|
|
32761
|
-
const modified =
|
|
32906
|
+
const modified = formatDateBR(item.lastModifiedDateTime);
|
|
32762
32907
|
const childCount = item.folder?.childCount != null ? ` — ${item.folder.childCount} itens` : "";
|
|
32763
32908
|
return `- ${icon} **${item.name}**${size}${childCount}
|
|
32764
32909
|
Modificado: ${modified}
|
|
@@ -32804,6 +32949,9 @@ function formatShareLink(result) {
|
|
|
32804
32949
|
}
|
|
32805
32950
|
|
|
32806
32951
|
// src/tools/onedrive-tools.ts
|
|
32952
|
+
function formatFileContent(content) {
|
|
32953
|
+
return typeof content === "string" ? content : JSON.stringify(content, null, 2);
|
|
32954
|
+
}
|
|
32807
32955
|
function registerOneDriveTools(server, onedrive) {
|
|
32808
32956
|
server.tool("list-drive-files", "Lista arquivos e pastas do OneDrive. Por padrão lista a raiz.", {
|
|
32809
32957
|
itemId: exports_external.string().optional().describe("ID do item/pasta para listar conteúdo"),
|
|
@@ -32820,12 +32968,17 @@ function registerOneDriveTools(server, onedrive) {
|
|
|
32820
32968
|
}, safeTool(async (params) => {
|
|
32821
32969
|
const content = await onedrive.readFileContent(params.itemId);
|
|
32822
32970
|
return {
|
|
32823
|
-
content: [
|
|
32824
|
-
|
|
32825
|
-
|
|
32826
|
-
|
|
32827
|
-
|
|
32828
|
-
|
|
32971
|
+
content: [{ type: "text", text: formatFileContent(content) }]
|
|
32972
|
+
};
|
|
32973
|
+
}));
|
|
32974
|
+
server.tool("read-shared-file-content", "Lê o conteúdo de um arquivo de um drive compartilhado (SharePoint ou OneDrive de outro usuário). Use o driveId e itemId retornados por search-sharepoint ou list-library-items.", {
|
|
32975
|
+
driveId: exports_external.string().describe("ID do drive compartilhado"),
|
|
32976
|
+
itemId: exports_external.string().optional().describe("ID do arquivo no drive compartilhado"),
|
|
32977
|
+
path: exports_external.string().optional().describe("Caminho do arquivo no drive (alternativa ao itemId, ex: 'Documents/pasta/arquivo.docx')")
|
|
32978
|
+
}, safeTool(async (params) => {
|
|
32979
|
+
const content = await onedrive.readSharedFileContent(params);
|
|
32980
|
+
return {
|
|
32981
|
+
content: [{ type: "text", text: formatFileContent(content) }]
|
|
32829
32982
|
};
|
|
32830
32983
|
}));
|
|
32831
32984
|
server.tool("upload-file", "Faz upload de um arquivo para o OneDrive (até 4MB de conteúdo texto).", {
|
|
@@ -32902,7 +33055,7 @@ function formatLibraryItems(items) {
|
|
|
32902
33055
|
const formatted = items.map((item) => {
|
|
32903
33056
|
const isFolder = !!item.folder;
|
|
32904
33057
|
const icon = isFolder ? "[pasta]" : "[arquivo]";
|
|
32905
|
-
const size = item.size ? ` (${item.size}
|
|
33058
|
+
const size = item.size ? ` (${formatSize(item.size)})` : "";
|
|
32906
33059
|
return `- ${icon} **${item.name}**${size}
|
|
32907
33060
|
URL: ${item.webUrl}
|
|
32908
33061
|
ID: ${item.id}`;
|
|
@@ -33007,7 +33160,7 @@ function formatChannelMessages(messages) {
|
|
|
33007
33160
|
return "Nenhuma mensagem encontrada.";
|
|
33008
33161
|
const formatted = messages.map((m) => {
|
|
33009
33162
|
const from = messageSenderName(m);
|
|
33010
|
-
const date4 =
|
|
33163
|
+
const date4 = formatDateBR(m.createdDateTime);
|
|
33011
33164
|
const content = m.body?.content?.substring(0, MESSAGE_CONTENT_MAX_LENGTH) ?? "";
|
|
33012
33165
|
return `- **${from}** (${date4})
|
|
33013
33166
|
${content}`;
|
|
@@ -33024,7 +33177,7 @@ function formatChatList(chats) {
|
|
|
33024
33177
|
const formatted = chats.map((c) => {
|
|
33025
33178
|
const topic = c.topic ?? "Chat sem título";
|
|
33026
33179
|
const type = c.chatType ?? "unknown";
|
|
33027
|
-
const updated = c.lastUpdatedDateTime ?
|
|
33180
|
+
const updated = c.lastUpdatedDateTime ? formatDateBR(c.lastUpdatedDateTime) : "N/A";
|
|
33028
33181
|
const members = c.members?.map((m) => m.displayName).join(", ") ?? "";
|
|
33029
33182
|
return `- **${topic}** (${type})
|
|
33030
33183
|
Membros: ${members}
|
|
@@ -33102,14 +33255,14 @@ function registerTeamsTools(server, teams) {
|
|
|
33102
33255
|
// src/index.ts
|
|
33103
33256
|
var server = new McpServer({
|
|
33104
33257
|
name: "office365-mcp-server",
|
|
33105
|
-
version:
|
|
33258
|
+
version: package_default.version
|
|
33106
33259
|
});
|
|
33107
33260
|
var mailService = createMailService(msalClient);
|
|
33108
33261
|
var calendarService = createCalendarService(msalClient);
|
|
33109
33262
|
var oneDriveService = createOneDriveService(msalClient);
|
|
33110
33263
|
var sharePointService = createSharePointService(msalClient);
|
|
33111
33264
|
var teamsService = createTeamsService(msalClient);
|
|
33112
|
-
registerAuthTools(server);
|
|
33265
|
+
registerAuthTools(server, msalClient);
|
|
33113
33266
|
registerMailTools(server, mailService);
|
|
33114
33267
|
registerCalendarTools(server, calendarService);
|
|
33115
33268
|
registerOneDriveTools(server, oneDriveService);
|
package/package.json
CHANGED