@softeria/ms-365-mcp-server 0.11.4 → 0.12.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/.releaserc.json +12 -0
- package/README.md +2 -1
- package/bin/modules/simplified-openapi.mjs +465 -274
- package/dist/auth-tools.js +181 -173
- package/dist/auth.js +402 -415
- package/dist/cli.js +35 -36
- package/dist/generated/client.js +6976 -14312
- package/dist/generated/endpoint-types.js +0 -1
- package/dist/generated/hack.js +39 -33
- package/dist/graph-client.js +426 -473
- package/dist/graph-tools.js +217 -228
- package/dist/index.js +76 -79
- package/dist/lib/microsoft-auth.js +62 -72
- package/dist/logger.js +36 -27
- package/dist/oauth-provider.js +48 -47
- package/dist/server.js +277 -264
- package/dist/version.js +9 -6
- package/package.json +13 -3
- package/tsup.config.ts +30 -0
- package/bin/release.mjs +0 -69
package/dist/graph-tools.js
CHANGED
|
@@ -1,238 +1,227 @@
|
|
|
1
|
-
import logger from
|
|
2
|
-
import { api } from
|
|
3
|
-
import { z } from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
logger.error(`Invalid tool filter regex pattern: ${enabledToolsPattern}. Ignoring filter.`);
|
|
13
|
-
}
|
|
1
|
+
import logger from "./logger.js";
|
|
2
|
+
import { api } from "./generated/client.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
function registerGraphTools(server, graphClient, readOnly = false, enabledToolsPattern) {
|
|
5
|
+
let enabledToolsRegex;
|
|
6
|
+
if (enabledToolsPattern) {
|
|
7
|
+
try {
|
|
8
|
+
enabledToolsRegex = new RegExp(enabledToolsPattern, "i");
|
|
9
|
+
logger.info(`Tool filtering enabled with pattern: ${enabledToolsPattern}`);
|
|
10
|
+
} catch (error) {
|
|
11
|
+
logger.error(`Invalid tool filter regex pattern: ${enabledToolsPattern}. Ignoring filter.`);
|
|
14
12
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
}
|
|
14
|
+
for (const tool of api.endpoints) {
|
|
15
|
+
if (readOnly && tool.method.toUpperCase() !== "GET") {
|
|
16
|
+
logger.info(`Skipping write operation ${tool.alias} in read-only mode`);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (enabledToolsRegex && !enabledToolsRegex.test(tool.alias)) {
|
|
20
|
+
logger.info(`Skipping tool ${tool.alias} - doesn't match filter pattern`);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const paramSchema = {};
|
|
24
|
+
if (tool.parameters && tool.parameters.length > 0) {
|
|
25
|
+
for (const param of tool.parameters) {
|
|
26
|
+
if (param.type === "Body" && param.schema) {
|
|
27
|
+
paramSchema[param.name] = z.union([z.string(), param.schema]);
|
|
28
|
+
} else {
|
|
29
|
+
paramSchema[param.name] = param.schema || z.any();
|
|
23
30
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (tool.method.toUpperCase() === "GET" && tool.path.includes("/")) {
|
|
34
|
+
paramSchema["fetchAllPages"] = z.boolean().describe("Automatically fetch all pages of results").optional();
|
|
35
|
+
}
|
|
36
|
+
server.tool(
|
|
37
|
+
tool.alias,
|
|
38
|
+
tool.description ?? "",
|
|
39
|
+
paramSchema,
|
|
40
|
+
{
|
|
41
|
+
title: tool.alias,
|
|
42
|
+
readOnlyHint: tool.method.toUpperCase() === "GET"
|
|
43
|
+
},
|
|
44
|
+
async (params, extra) => {
|
|
45
|
+
logger.info(`Tool ${tool.alias} called with params: ${JSON.stringify(params)}`);
|
|
46
|
+
try {
|
|
47
|
+
logger.info(`params: ${JSON.stringify(params)}`);
|
|
48
|
+
const parameterDefinitions = tool.parameters || [];
|
|
49
|
+
let path = tool.path;
|
|
50
|
+
const queryParams = {};
|
|
51
|
+
const headers = {};
|
|
52
|
+
let body = null;
|
|
53
|
+
for (let [paramName, paramValue] of Object.entries(params)) {
|
|
54
|
+
if (paramName === "fetchAllPages") {
|
|
55
|
+
continue;
|
|
33
56
|
}
|
|
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
|
-
// Ok, so, MCP clients (such as claude code) doesn't support $ in parameter names,
|
|
59
|
-
// and others might not support __, so we strip them in hack.ts and restore them here
|
|
60
|
-
const odataParams = [
|
|
61
|
-
'filter',
|
|
62
|
-
'select',
|
|
63
|
-
'expand',
|
|
64
|
-
'orderby',
|
|
65
|
-
'skip',
|
|
66
|
-
'top',
|
|
67
|
-
'count',
|
|
68
|
-
'search',
|
|
69
|
-
'format',
|
|
70
|
-
];
|
|
71
|
-
const fixedParamName = odataParams.includes(paramName.toLowerCase())
|
|
72
|
-
? `$${paramName.toLowerCase()}`
|
|
73
|
-
: paramName;
|
|
74
|
-
const paramDef = parameterDefinitions.find((p) => p.name === paramName);
|
|
75
|
-
if (paramDef) {
|
|
76
|
-
switch (paramDef.type) {
|
|
77
|
-
case 'Path':
|
|
78
|
-
path = path
|
|
79
|
-
.replace(`{${paramName}}`, encodeURIComponent(paramValue))
|
|
80
|
-
.replace(`:${paramName}`, encodeURIComponent(paramValue));
|
|
81
|
-
break;
|
|
82
|
-
case 'Query':
|
|
83
|
-
queryParams[fixedParamName] = `${paramValue}`;
|
|
84
|
-
break;
|
|
85
|
-
case 'Body':
|
|
86
|
-
if (typeof paramValue === 'string') {
|
|
87
|
-
try {
|
|
88
|
-
body = JSON.parse(paramValue);
|
|
89
|
-
}
|
|
90
|
-
catch (e) {
|
|
91
|
-
body = paramValue;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
body = paramValue;
|
|
96
|
-
}
|
|
97
|
-
break;
|
|
98
|
-
case 'Header':
|
|
99
|
-
headers[fixedParamName] = `${paramValue}`;
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
else if (paramName === 'body') {
|
|
104
|
-
if (typeof paramValue === 'string') {
|
|
105
|
-
try {
|
|
106
|
-
body = JSON.parse(paramValue);
|
|
107
|
-
}
|
|
108
|
-
catch (e) {
|
|
109
|
-
body = paramValue;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
body = paramValue;
|
|
114
|
-
}
|
|
115
|
-
logger.info(`Set legacy body param: ${JSON.stringify(body)}`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (Object.keys(queryParams).length > 0) {
|
|
119
|
-
const queryString = Object.entries(queryParams)
|
|
120
|
-
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
|
121
|
-
.join('&');
|
|
122
|
-
path = `${path}${path.includes('?') ? '&' : '?'}${queryString}`;
|
|
123
|
-
}
|
|
124
|
-
const options = {
|
|
125
|
-
method: tool.method.toUpperCase(),
|
|
126
|
-
headers,
|
|
127
|
-
};
|
|
128
|
-
if (options.method !== 'GET' && body) {
|
|
129
|
-
options.body = typeof body === 'string' ? body : JSON.stringify(body);
|
|
130
|
-
}
|
|
131
|
-
const isProbablyMediaContent = tool.errors?.some((error) => error.description === 'Retrieved media content') ||
|
|
132
|
-
path.endsWith('/content');
|
|
133
|
-
if (isProbablyMediaContent) {
|
|
134
|
-
options.rawResponse = true;
|
|
135
|
-
}
|
|
136
|
-
logger.info(`Making graph request to ${path} with options: ${JSON.stringify(options)}`);
|
|
137
|
-
let response = await graphClient.graphRequest(path, options);
|
|
138
|
-
const fetchAllPages = params.fetchAllPages === true;
|
|
139
|
-
if (fetchAllPages && response && response.content && response.content.length > 0) {
|
|
57
|
+
const odataParams = [
|
|
58
|
+
"filter",
|
|
59
|
+
"select",
|
|
60
|
+
"expand",
|
|
61
|
+
"orderby",
|
|
62
|
+
"skip",
|
|
63
|
+
"top",
|
|
64
|
+
"count",
|
|
65
|
+
"search",
|
|
66
|
+
"format"
|
|
67
|
+
];
|
|
68
|
+
const fixedParamName = odataParams.includes(paramName.toLowerCase()) ? `$${paramName.toLowerCase()}` : paramName;
|
|
69
|
+
const paramDef = parameterDefinitions.find((p) => p.name === paramName);
|
|
70
|
+
if (paramDef) {
|
|
71
|
+
switch (paramDef.type) {
|
|
72
|
+
case "Path":
|
|
73
|
+
path = path.replace(`{${paramName}}`, encodeURIComponent(paramValue)).replace(`:${paramName}`, encodeURIComponent(paramValue));
|
|
74
|
+
break;
|
|
75
|
+
case "Query":
|
|
76
|
+
queryParams[fixedParamName] = `${paramValue}`;
|
|
77
|
+
break;
|
|
78
|
+
case "Body":
|
|
79
|
+
if (typeof paramValue === "string") {
|
|
140
80
|
try {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
let pageCount = 1;
|
|
145
|
-
while (nextLink) {
|
|
146
|
-
logger.info(`Fetching page ${pageCount + 1} from: ${nextLink}`);
|
|
147
|
-
const url = new URL(nextLink);
|
|
148
|
-
const nextPath = url.pathname.replace('/v1.0', '');
|
|
149
|
-
const nextOptions = { ...options };
|
|
150
|
-
const nextQueryParams = {};
|
|
151
|
-
for (const [key, value] of url.searchParams.entries()) {
|
|
152
|
-
nextQueryParams[key] = value;
|
|
153
|
-
}
|
|
154
|
-
nextOptions.queryParams = nextQueryParams;
|
|
155
|
-
const nextResponse = await graphClient.graphRequest(nextPath, nextOptions);
|
|
156
|
-
if (nextResponse && nextResponse.content && nextResponse.content.length > 0) {
|
|
157
|
-
const nextJsonResponse = JSON.parse(nextResponse.content[0].text);
|
|
158
|
-
if (nextJsonResponse.value && Array.isArray(nextJsonResponse.value)) {
|
|
159
|
-
allItems = allItems.concat(nextJsonResponse.value);
|
|
160
|
-
}
|
|
161
|
-
nextLink = nextJsonResponse['@odata.nextLink'];
|
|
162
|
-
pageCount++;
|
|
163
|
-
if (pageCount > 100) {
|
|
164
|
-
logger.warn(`Reached maximum page limit (100) for pagination`);
|
|
165
|
-
break;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
combinedResponse.value = allItems;
|
|
173
|
-
if (combinedResponse['@odata.count']) {
|
|
174
|
-
combinedResponse['@odata.count'] = allItems.length;
|
|
175
|
-
}
|
|
176
|
-
delete combinedResponse['@odata.nextLink'];
|
|
177
|
-
response.content[0].text = JSON.stringify(combinedResponse);
|
|
178
|
-
logger.info(`Pagination complete: collected ${allItems.length} items across ${pageCount} pages`);
|
|
179
|
-
}
|
|
180
|
-
catch (e) {
|
|
181
|
-
logger.error(`Error during pagination: ${e}`);
|
|
81
|
+
body = JSON.parse(paramValue);
|
|
82
|
+
} catch (e) {
|
|
83
|
+
body = paramValue;
|
|
182
84
|
}
|
|
85
|
+
} else {
|
|
86
|
+
body = paramValue;
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
case "Header":
|
|
90
|
+
headers[fixedParamName] = `${paramValue}`;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
} else if (paramName === "body") {
|
|
94
|
+
if (typeof paramValue === "string") {
|
|
95
|
+
try {
|
|
96
|
+
body = JSON.parse(paramValue);
|
|
97
|
+
} catch (e) {
|
|
98
|
+
body = paramValue;
|
|
183
99
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
100
|
+
} else {
|
|
101
|
+
body = paramValue;
|
|
102
|
+
}
|
|
103
|
+
logger.info(`Set legacy body param: ${JSON.stringify(body)}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (Object.keys(queryParams).length > 0) {
|
|
107
|
+
const queryString = Object.entries(queryParams).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
108
|
+
path = `${path}${path.includes("?") ? "&" : "?"}${queryString}`;
|
|
109
|
+
}
|
|
110
|
+
const options = {
|
|
111
|
+
method: tool.method.toUpperCase(),
|
|
112
|
+
headers
|
|
113
|
+
};
|
|
114
|
+
if (options.method !== "GET" && body) {
|
|
115
|
+
options.body = typeof body === "string" ? body : JSON.stringify(body);
|
|
116
|
+
}
|
|
117
|
+
const isProbablyMediaContent = tool.errors?.some((error) => error.description === "Retrieved media content") || path.endsWith("/content");
|
|
118
|
+
if (isProbablyMediaContent) {
|
|
119
|
+
options.rawResponse = true;
|
|
120
|
+
}
|
|
121
|
+
logger.info(`Making graph request to ${path} with options: ${JSON.stringify(options)}`);
|
|
122
|
+
let response = await graphClient.graphRequest(path, options);
|
|
123
|
+
const fetchAllPages = params.fetchAllPages === true;
|
|
124
|
+
if (fetchAllPages && response && response.content && response.content.length > 0) {
|
|
125
|
+
try {
|
|
126
|
+
let combinedResponse = JSON.parse(response.content[0].text);
|
|
127
|
+
let allItems = combinedResponse.value || [];
|
|
128
|
+
let nextLink = combinedResponse["@odata.nextLink"];
|
|
129
|
+
let pageCount = 1;
|
|
130
|
+
while (nextLink) {
|
|
131
|
+
logger.info(`Fetching page ${pageCount + 1} from: ${nextLink}`);
|
|
132
|
+
const url = new URL(nextLink);
|
|
133
|
+
const nextPath = url.pathname.replace("/v1.0", "");
|
|
134
|
+
const nextOptions = { ...options };
|
|
135
|
+
const nextQueryParams = {};
|
|
136
|
+
for (const [key, value] of url.searchParams.entries()) {
|
|
137
|
+
nextQueryParams[key] = value;
|
|
138
|
+
}
|
|
139
|
+
nextOptions.queryParams = nextQueryParams;
|
|
140
|
+
const nextResponse = await graphClient.graphRequest(nextPath, nextOptions);
|
|
141
|
+
if (nextResponse && nextResponse.content && nextResponse.content.length > 0) {
|
|
142
|
+
const nextJsonResponse = JSON.parse(nextResponse.content[0].text);
|
|
143
|
+
if (nextJsonResponse.value && Array.isArray(nextJsonResponse.value)) {
|
|
144
|
+
allItems = allItems.concat(nextJsonResponse.value);
|
|
145
|
+
}
|
|
146
|
+
nextLink = nextJsonResponse["@odata.nextLink"];
|
|
147
|
+
pageCount++;
|
|
148
|
+
if (pageCount > 100) {
|
|
149
|
+
logger.warn(`Reached maximum page limit (100) for pagination`);
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
break;
|
|
206
154
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
isError: response.isError,
|
|
220
|
-
};
|
|
221
|
-
return result;
|
|
155
|
+
}
|
|
156
|
+
combinedResponse.value = allItems;
|
|
157
|
+
if (combinedResponse["@odata.count"]) {
|
|
158
|
+
combinedResponse["@odata.count"] = allItems.length;
|
|
159
|
+
}
|
|
160
|
+
delete combinedResponse["@odata.nextLink"];
|
|
161
|
+
response.content[0].text = JSON.stringify(combinedResponse);
|
|
162
|
+
logger.info(
|
|
163
|
+
`Pagination complete: collected ${allItems.length} items across ${pageCount} pages`
|
|
164
|
+
);
|
|
165
|
+
} catch (e) {
|
|
166
|
+
logger.error(`Error during pagination: ${e}`);
|
|
222
167
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
168
|
+
}
|
|
169
|
+
if (response && response.content && response.content.length > 0) {
|
|
170
|
+
const responseText = response.content[0].text;
|
|
171
|
+
const responseSize = responseText.length;
|
|
172
|
+
logger.info(`Response size: ${responseSize} characters`);
|
|
173
|
+
try {
|
|
174
|
+
const jsonResponse = JSON.parse(responseText);
|
|
175
|
+
if (jsonResponse.value && Array.isArray(jsonResponse.value)) {
|
|
176
|
+
logger.info(`Response contains ${jsonResponse.value.length} items`);
|
|
177
|
+
if (jsonResponse.value.length > 0 && jsonResponse.value[0].body) {
|
|
178
|
+
logger.info(
|
|
179
|
+
`First item has body field with size: ${JSON.stringify(jsonResponse.value[0].body).length} characters`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (jsonResponse["@odata.nextLink"]) {
|
|
184
|
+
logger.info(`Response has pagination nextLink: ${jsonResponse["@odata.nextLink"]}`);
|
|
185
|
+
}
|
|
186
|
+
const preview = responseText.substring(0, 500);
|
|
187
|
+
logger.info(`Response preview: ${preview}${responseText.length > 500 ? "..." : ""}`);
|
|
188
|
+
} catch (e) {
|
|
189
|
+
const preview = responseText.substring(0, 500);
|
|
190
|
+
logger.info(
|
|
191
|
+
`Response preview (non-JSON): ${preview}${responseText.length > 500 ? "..." : ""}`
|
|
192
|
+
);
|
|
235
193
|
}
|
|
236
|
-
|
|
237
|
-
|
|
194
|
+
}
|
|
195
|
+
const content = response.content.map((item) => {
|
|
196
|
+
const textContent = {
|
|
197
|
+
type: "text",
|
|
198
|
+
text: item.text
|
|
199
|
+
};
|
|
200
|
+
return textContent;
|
|
201
|
+
});
|
|
202
|
+
const result = {
|
|
203
|
+
content,
|
|
204
|
+
_meta: response._meta,
|
|
205
|
+
isError: response.isError
|
|
206
|
+
};
|
|
207
|
+
return result;
|
|
208
|
+
} catch (error) {
|
|
209
|
+
logger.error(`Error in tool ${tool.alias}: ${error.message}`);
|
|
210
|
+
const errorContent = {
|
|
211
|
+
type: "text",
|
|
212
|
+
text: JSON.stringify({
|
|
213
|
+
error: `Error in tool ${tool.alias}: ${error.message}`
|
|
214
|
+
})
|
|
215
|
+
};
|
|
216
|
+
return {
|
|
217
|
+
content: [errorContent],
|
|
218
|
+
isError: true
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
}
|
|
238
224
|
}
|
|
225
|
+
export {
|
|
226
|
+
registerGraphTools
|
|
227
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,86 +1,83 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import { parseArgs } from
|
|
4
|
-
import logger from
|
|
5
|
-
import AuthManager from
|
|
6
|
-
import MicrosoftGraphServer from
|
|
7
|
-
import { version } from
|
|
8
|
-
import { buildScopesFromEndpoints } from
|
|
2
|
+
import "dotenv/config";
|
|
3
|
+
import { parseArgs } from "./cli.js";
|
|
4
|
+
import logger from "./logger.js";
|
|
5
|
+
import AuthManager from "./auth.js";
|
|
6
|
+
import MicrosoftGraphServer from "./server.js";
|
|
7
|
+
import { version } from "./version.js";
|
|
8
|
+
import { buildScopesFromEndpoints } from "./auth.js";
|
|
9
9
|
async function main() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
const scopes = buildScopesFromEndpoints(includeWorkScopes);
|
|
23
|
-
const authManager = new AuthManager(undefined, scopes);
|
|
24
|
-
await authManager.loadTokenCache();
|
|
25
|
-
if (args.login) {
|
|
26
|
-
await authManager.acquireTokenByDeviceCode();
|
|
27
|
-
logger.info('Login completed, testing connection with Graph API...');
|
|
28
|
-
const result = await authManager.testLogin();
|
|
29
|
-
console.log(JSON.stringify(result));
|
|
30
|
-
process.exit(0);
|
|
31
|
-
}
|
|
32
|
-
if (args.verifyLogin) {
|
|
33
|
-
logger.info('Verifying login...');
|
|
34
|
-
const result = await authManager.testLogin();
|
|
35
|
-
console.log(JSON.stringify(result));
|
|
36
|
-
process.exit(0);
|
|
37
|
-
}
|
|
38
|
-
if (args.logout) {
|
|
39
|
-
await authManager.logout();
|
|
40
|
-
console.log(JSON.stringify({ message: 'Logged out successfully' }));
|
|
41
|
-
process.exit(0);
|
|
42
|
-
}
|
|
43
|
-
if (args.listAccounts) {
|
|
44
|
-
const accounts = await authManager.listAccounts();
|
|
45
|
-
const selectedAccountId = authManager.getSelectedAccountId();
|
|
46
|
-
const result = accounts.map(account => ({
|
|
47
|
-
id: account.homeAccountId,
|
|
48
|
-
username: account.username,
|
|
49
|
-
name: account.name,
|
|
50
|
-
selected: account.homeAccountId === selectedAccountId
|
|
51
|
-
}));
|
|
52
|
-
console.log(JSON.stringify({ accounts: result }));
|
|
53
|
-
process.exit(0);
|
|
54
|
-
}
|
|
55
|
-
if (args.selectAccount) {
|
|
56
|
-
const success = await authManager.selectAccount(args.selectAccount);
|
|
57
|
-
if (success) {
|
|
58
|
-
console.log(JSON.stringify({ message: `Selected account: ${args.selectAccount}` }));
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
console.log(JSON.stringify({ error: `Account not found: ${args.selectAccount}` }));
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
process.exit(0);
|
|
65
|
-
}
|
|
66
|
-
if (args.removeAccount) {
|
|
67
|
-
const success = await authManager.removeAccount(args.removeAccount);
|
|
68
|
-
if (success) {
|
|
69
|
-
console.log(JSON.stringify({ message: `Removed account: ${args.removeAccount}` }));
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
console.log(JSON.stringify({ error: `Account not found: ${args.removeAccount}` }));
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
process.exit(0);
|
|
76
|
-
}
|
|
77
|
-
const server = new MicrosoftGraphServer(authManager, args);
|
|
78
|
-
await server.initialize(version);
|
|
79
|
-
await server.start();
|
|
10
|
+
try {
|
|
11
|
+
const args = parseArgs();
|
|
12
|
+
let includeWorkScopes = args.forceWorkScopes;
|
|
13
|
+
if (!includeWorkScopes) {
|
|
14
|
+
const tempAuthManager = new AuthManager(void 0, buildScopesFromEndpoints(false));
|
|
15
|
+
await tempAuthManager.loadTokenCache();
|
|
16
|
+
const hasWorkPermissions = await tempAuthManager.hasWorkAccountPermissions();
|
|
17
|
+
if (hasWorkPermissions) {
|
|
18
|
+
includeWorkScopes = true;
|
|
19
|
+
logger.info("Detected existing work account permissions, including work scopes");
|
|
20
|
+
}
|
|
80
21
|
}
|
|
81
|
-
|
|
82
|
-
|
|
22
|
+
const scopes = buildScopesFromEndpoints(includeWorkScopes);
|
|
23
|
+
const authManager = new AuthManager(void 0, scopes);
|
|
24
|
+
await authManager.loadTokenCache();
|
|
25
|
+
if (args.login) {
|
|
26
|
+
await authManager.acquireTokenByDeviceCode();
|
|
27
|
+
logger.info("Login completed, testing connection with Graph API...");
|
|
28
|
+
const result = await authManager.testLogin();
|
|
29
|
+
console.log(JSON.stringify(result));
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
if (args.verifyLogin) {
|
|
33
|
+
logger.info("Verifying login...");
|
|
34
|
+
const result = await authManager.testLogin();
|
|
35
|
+
console.log(JSON.stringify(result));
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
if (args.logout) {
|
|
39
|
+
await authManager.logout();
|
|
40
|
+
console.log(JSON.stringify({ message: "Logged out successfully" }));
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
if (args.listAccounts) {
|
|
44
|
+
const accounts = await authManager.listAccounts();
|
|
45
|
+
const selectedAccountId = authManager.getSelectedAccountId();
|
|
46
|
+
const result = accounts.map((account) => ({
|
|
47
|
+
id: account.homeAccountId,
|
|
48
|
+
username: account.username,
|
|
49
|
+
name: account.name,
|
|
50
|
+
selected: account.homeAccountId === selectedAccountId
|
|
51
|
+
}));
|
|
52
|
+
console.log(JSON.stringify({ accounts: result }));
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
if (args.selectAccount) {
|
|
56
|
+
const success = await authManager.selectAccount(args.selectAccount);
|
|
57
|
+
if (success) {
|
|
58
|
+
console.log(JSON.stringify({ message: `Selected account: ${args.selectAccount}` }));
|
|
59
|
+
} else {
|
|
60
|
+
console.log(JSON.stringify({ error: `Account not found: ${args.selectAccount}` }));
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
if (args.removeAccount) {
|
|
66
|
+
const success = await authManager.removeAccount(args.removeAccount);
|
|
67
|
+
if (success) {
|
|
68
|
+
console.log(JSON.stringify({ message: `Removed account: ${args.removeAccount}` }));
|
|
69
|
+
} else {
|
|
70
|
+
console.log(JSON.stringify({ error: `Account not found: ${args.removeAccount}` }));
|
|
83
71
|
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
process.exit(0);
|
|
84
74
|
}
|
|
75
|
+
const server = new MicrosoftGraphServer(authManager, args);
|
|
76
|
+
await server.initialize(version);
|
|
77
|
+
await server.start();
|
|
78
|
+
} catch (error) {
|
|
79
|
+
logger.error(`Startup error: ${error}`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
85
82
|
}
|
|
86
83
|
main();
|