@softeria/ms-365-mcp-server 0.157.2 → 0.158.1

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/README.md CHANGED
@@ -182,6 +182,80 @@ npx @softeria/ms-365-mcp-server \
182
182
 
183
183
  In HTTP mode, OAuth discovery advertises the effective filtered permissions so clients request the same consent surface. On-Behalf-Of mode (`--obo`) still advertises `api://<clientId>/access_as_user` for protected-resource metadata; `--allowed-scopes` does not override OBO.
184
184
 
185
+ ### Restricting user profile fields
186
+
187
+ Deployments can set a comma-separated field filter for selected user-directory paths with
188
+ `--user-fields` or `MS365_MCP_USER_FIELDS`. It narrows the `$select` sent to Microsoft Graph
189
+ on `/users` reads and projects responses on the covered paths listed below. This is a
190
+ path-specific data filter, **not a complete Graph authorization boundary**: other Graph
191
+ routes and resource shapes can expose overlapping profile data.
192
+
193
+ ```bash
194
+ npx @softeria/ms-365-mcp-server \
195
+ --org-mode \
196
+ --user-fields 'id,displayName,mail,userPrincipalName'
197
+ ```
198
+
199
+ The filter is keyed on known Graph paths rather than tool names. It applies to direct tools,
200
+ discovery mode's `execute-tool`, and matching `graph-batch` subrequests. Batch subrequest URLs
201
+ are rewritten on covered `/users` reads, and responses are projected on all covered profile
202
+ paths. The byte-passthrough tools (`download-bytes`, `download-bytes-to-file`,
203
+ `get-download-url`) return responses verbatim and refuse targets matching the covered user
204
+ profile paths while the filter is active.
205
+
206
+ Two levels of enforcement apply, depending on what Graph returns:
207
+
208
+ | Path | Enforcement |
209
+ | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
210
+ | `/users`, `/users/{id}` | `$select` is narrowed on the request and the response is projected, so excluded fields never leave the tenant |
211
+ | `/me/manager`, `/me/directReports`, `/users/{id}/manager`, `/users/{id}/directReports`, `/groups/{id}/members`, `/groups/{id}/owners` | The response is projected. These are typed as `directoryObject`, where Graph requires an OData cast before it will `$select` a user-only property such as `jobTitle`, so narrowing the request would risk breaking calls that work today |
212
+
213
+ While the filter is active, `$expand` is removed from `/me`, `/groups`, and `/groups/{id}`
214
+ requests because those resources can expand to related user profiles. This also applies to
215
+ matching batch subrequests. The base `/me` and group responses are otherwise not projected.
216
+
217
+ This does **not** cover every route that can return a user-shaped object. In particular,
218
+ generic Graph access can still reach alternate routes or representations such as
219
+ `/directoryObjects/{id}`, `/groups/{id}/transitiveMembers`, or `/users('{id}')`. Those are
220
+ not currently normalized to the covered paths. If this setting is a security requirement,
221
+ also restrict generic Graph access (for example `graph-batch`) and validate the effective
222
+ tool surface for your deployment; do not rely on `--user-fields` alone as a tenant-wide
223
+ data-access control.
224
+
225
+ Resources below a user, such as `/users/{id}/messages` or `/users/{id}/photo/$value`, are
226
+ mail, calendar and binary resources rather than profile properties, and are unaffected. The
227
+ signed-in user's own `/me` profile is also unaffected, as are the Teams and chat member
228
+ lists, which return `conversationMember` rather than user profiles.
229
+
230
+ #### Known gap: `list-relevant-people`
231
+
232
+ `list-relevant-people` (`/me/people`) is **not** covered. It returns `person` resources,
233
+ a different type whose properties only partly overlap with `user` — it carries `jobTitle`,
234
+ `department` and `officeLocation`, but addresses arrive as `scoredEmailAddresses` rather
235
+ than `mail`. Applying a user-field allowlist to it would reject valid field names and
236
+ narrow the result to something the tool could not use.
237
+
238
+ Deployments that need the people surface closed as well should drop the tool from the
239
+ surface, for example with `--enabled-tools` or by choosing a preset that excludes it:
240
+
241
+ ```bash
242
+ npx @softeria/ms-365-mcp-server \
243
+ --org-mode \
244
+ --user-fields 'id,displayName,mail' \
245
+ --enabled-tools '^(?!list-relevant-people$).*'
246
+ ```
247
+
248
+ CLI values take precedence over the environment variable. A value that names no fields fails
249
+ at startup. When neither is configured, existing behavior is unchanged. Configure this in
250
+ the LibreChat MCP server environment or command arguments; project-local `.env` files are
251
+ intentionally restricted to application credentials and are not used for this setting.
252
+
253
+ The allowlist is exhaustive for user properties: unlike an ordinary `$select`, `id` is only
254
+ returned when it appears in the list, so include it if downstream tools need it to address a
255
+ user. Collection annotations such as `@odata.nextLink` are retained so paging keeps working.
256
+ If Graph returns none of the allowlisted properties, the response is projected to empty
257
+ rather than returned untrimmed.
258
+
185
259
  ### Requesting extra scopes
186
260
 
187
261
  `--allowed-scopes` only ever _narrows_ the token request. To request a Graph scope that no bundled tool needs — for example to drive an endpoint via `graph-batch` — use `--extra-scopes` (or `MS365_MCP_EXTRA_SCOPES`). These scopes are appended verbatim to the token request, on top of the tool-derived scopes.