@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 +74 -0
- package/dist/__tests__/graph-tools.test.js +407 -120
- package/dist/cli.js +13 -1
- package/dist/generated/client-beta.js +1 -0
- package/dist/generated/client.js +10 -1
- package/dist/graph-tools.js +250 -55
- package/dist/lib/attachment-tickets.js +11 -1
- package/dist/lib/select-projection.js +9 -8
- package/dist/lib/user-field-policy.js +69 -0
- package/dist/server.js +32 -43
- package/package.json +1 -1
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.
|