@softeria/ms-365-mcp-server 0.114.3 → 0.114.4

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.
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { getRequestTokens } from "./request-context.js";
2
3
  function registerAuthTools(server, authManager) {
3
4
  server.tool(
4
5
  "login",
@@ -121,6 +122,7 @@ function registerAuthTools(server, authManager) {
121
122
  const accounts = await authManager.listAccounts();
122
123
  const selectedAccountId = authManager.getSelectedAccountId();
123
124
  const pinnedMode = authManager.hasExpectedAccount();
125
+ const oauthBearerMode = authManager.isOAuthModeEnabled() || Boolean(getRequestTokens());
124
126
  const result = accounts.map((account) => ({
125
127
  email: account.username || "unknown",
126
128
  name: account.name,
@@ -133,7 +135,7 @@ function registerAuthTools(server, authManager) {
133
135
  text: JSON.stringify({
134
136
  accounts: result,
135
137
  count: result.length,
136
- tip: pinnedMode ? "Expected account pinning is configured; account parameters are disabled." : "Pass the 'email' value as the 'account' parameter in any tool call to target a specific account."
138
+ tip: pinnedMode ? "Expected account pinning is configured; account parameters are disabled." : oauthBearerMode ? "This server is in HTTP/OAuth mode: every request uses the identity of the connecting client's bearer token. The cached accounts listed here cannot be targeted via the 'account' parameter; reconnect the MCP client as the desired account instead." : "Pass the 'email' value as the 'account' parameter in any tool call to target a specific account."
137
139
  })
138
140
  }
139
141
  ]
package/dist/auth.js CHANGED
@@ -718,6 +718,11 @@ class AuthManager {
718
718
  */
719
719
  async getTokenForAccount(identifier) {
720
720
  if (this.isOAuthMode && this.oauthToken) {
721
+ if (identifier) {
722
+ throw new Error(
723
+ `Cannot switch to account '${identifier}': the server is in OAuth mode and always uses the identity of the supplied bearer token. Account switching requires stdio mode (or HTTP with --trust-proxy-auth).`
724
+ );
725
+ }
721
726
  return this.oauthToken;
722
727
  }
723
728
  let targetAccount = null;
@@ -46,6 +46,15 @@ function formatDisabledToolsForLog(disabledTools) {
46
46
  const suffix = disabledTools.length > shown.length ? `, ... +${disabledTools.length - shown.length} more` : "";
47
47
  return `${shown.join("; ")}${suffix}`;
48
48
  }
49
+ async function checkAccountParamInBearerMode(accountParam, authManager) {
50
+ if (!accountParam || !authManager) return null;
51
+ const contextToken = getRequestTokens()?.accessToken;
52
+ if (!contextToken && !authManager.isOAuthModeEnabled()) return null;
53
+ const bearerToken = contextToken ?? await authManager.getToken().catch(() => null) ?? void 0;
54
+ const bearerIdentity = getUserIdentityForAudit(bearerToken);
55
+ if (bearerIdentity && bearerIdentity.toLowerCase() === accountParam.toLowerCase()) return null;
56
+ return `The 'account' parameter is not supported in HTTP/OAuth mode: every request uses the identity of the connecting client's bearer token` + (bearerIdentity ? ` ('${bearerIdentity}')` : "") + `, so account switching is not possible. To act as '${accountParam}', reconnect the MCP client authenticated as that account, or run the server in stdio mode (or HTTP with --trust-proxy-auth) where cached accounts are available.`;
57
+ }
49
58
  const UTILITY_TOOLS = [
50
59
  {
51
60
  name: "parse-teams-url",
@@ -124,6 +133,13 @@ const UTILITY_TOOLS = [
124
133
  };
125
134
  }
126
135
  try {
136
+ const accountModeError = await checkAccountParamInBearerMode(accountParam, authManager);
137
+ if (accountModeError) {
138
+ return {
139
+ content: [{ type: "text", text: JSON.stringify({ error: accountModeError }) }],
140
+ isError: true
141
+ };
142
+ }
127
143
  let accountAccessToken;
128
144
  if (authManager && !authManager.isOAuthModeEnabled() && !getRequestTokens()) {
129
145
  accountAccessToken = await authManager.getTokenForAccount(accountParam);
@@ -158,9 +174,16 @@ async function executeGraphTool(tool, config, graphClient, params, authManager)
158
174
  const upn = getUserIdentityForAudit(getRequestTokens()?.accessToken);
159
175
  const httpMethod = tool.method.toUpperCase();
160
176
  try {
177
+ const accountParam = params.account;
178
+ const accountModeError = await checkAccountParamInBearerMode(accountParam, authManager);
179
+ if (accountModeError) {
180
+ return {
181
+ content: [{ type: "text", text: JSON.stringify({ error: accountModeError }) }],
182
+ isError: true
183
+ };
184
+ }
161
185
  let accountAccessToken;
162
186
  if (authManager && !authManager.isOAuthModeEnabled() && !getRequestTokens()) {
163
- const accountParam = params.account;
164
187
  try {
165
188
  accountAccessToken = await authManager.getTokenForAccount(accountParam);
166
189
  } catch (err) {
package/dist/server.js CHANGED
@@ -105,17 +105,24 @@ class MicrosoftGraphServer {
105
105
  async initialize(version) {
106
106
  this.secrets = await getSecrets();
107
107
  this.version = version;
108
- try {
109
- this.multiAccount = await this.authManager.isMultiAccount();
110
- if (this.multiAccount) {
111
- const accounts = await this.authManager.listAccounts();
112
- this.accountNames = accounts.map((a) => a.username).filter((u) => !!u);
113
- logger.info(
114
- `Multi-account mode detected (${this.accountNames.length} accounts): "account" parameter will be injected into all tool schemas`
115
- );
108
+ const accountRoutingAvailable = (!this.options.http || this.options.trustProxyAuth) && !this.authManager.isOAuthModeEnabled();
109
+ if (accountRoutingAvailable) {
110
+ try {
111
+ this.multiAccount = await this.authManager.isMultiAccount();
112
+ if (this.multiAccount) {
113
+ const accounts = await this.authManager.listAccounts();
114
+ this.accountNames = accounts.map((a) => a.username).filter((u) => !!u);
115
+ logger.info(
116
+ `Multi-account mode detected (${this.accountNames.length} accounts): "account" parameter will be injected into all tool schemas`
117
+ );
118
+ }
119
+ } catch (err) {
120
+ logger.warn(`Failed to detect multi-account mode: ${err.message}`);
116
121
  }
117
- } catch (err) {
118
- logger.warn(`Failed to detect multi-account mode: ${err.message}`);
122
+ } else {
123
+ logger.info(
124
+ 'Account routing disabled: requests use the OAuth bearer identity, so the "account" parameter is not injected into tool schemas'
125
+ );
119
126
  }
120
127
  if (this.options.obo) {
121
128
  if (!this.options.http) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softeria/ms-365-mcp-server",
3
- "version": "0.114.3",
3
+ "version": "0.114.4",
4
4
  "description": " A Model Context Protocol (MCP) server for interacting with Microsoft 365 and Office services through the Graph API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",