@softeria/ms-365-mcp-server 0.76.0 → 0.78.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.
@@ -944,6 +944,21 @@
944
944
  "toolName": "get-chat-message",
945
945
  "workScopes": ["ChatMessage.Read"]
946
946
  },
947
+ {
948
+ "pathPattern": "/chats/{chat-id}/messages/{chatMessage-id}/hostedContents",
949
+ "method": "get",
950
+ "toolName": "list-chat-message-hosted-contents",
951
+ "workScopes": ["ChatMessage.Read"],
952
+ "llmTip": "Lists hosted-content references (inline images, code snippets) attached to a Teams chat message. Returns an array of { id, contentType }. Use get-chat-message-hosted-content with the id to download the bytes. Hosted content IDs can also be parsed from the <img src> URL in the message body between /hostedContents/ and /$value."
953
+ },
954
+ {
955
+ "pathPattern": "/chats/{chat-id}/messages/{chatMessage-id}/hostedContents/{chatMessageHostedContent-id}/$value",
956
+ "method": "get",
957
+ "toolName": "get-chat-message-hosted-content",
958
+ "workScopes": ["ChatMessage.Read"],
959
+ "returnDownloadUrl": true,
960
+ "llmTip": "Returns raw bytes of a hosted content item (typically image/png or image/jpeg) attached to a Teams 1:1 or group chat message. Use list-chat-message-hosted-contents to discover IDs, or extract the ID from the <img src> URL in the message body."
961
+ },
947
962
  {
948
963
  "pathPattern": "/chats/{chat-id}/messages",
949
964
  "method": "post",
@@ -1005,6 +1020,21 @@
1005
1020
  "toolName": "get-channel-message",
1006
1021
  "workScopes": ["ChannelMessage.Read.All"]
1007
1022
  },
1023
+ {
1024
+ "pathPattern": "/teams/{team-id}/channels/{channel-id}/messages/{chatMessage-id}/hostedContents",
1025
+ "method": "get",
1026
+ "toolName": "list-channel-message-hosted-contents",
1027
+ "workScopes": ["ChannelMessage.Read.All"],
1028
+ "llmTip": "Lists hosted-content references (inline images, code snippets) attached to a Teams channel message. Returns an array of { id, contentType }. Use get-channel-message-hosted-content with the id to download bytes."
1029
+ },
1030
+ {
1031
+ "pathPattern": "/teams/{team-id}/channels/{channel-id}/messages/{chatMessage-id}/hostedContents/{chatMessageHostedContent-id}/$value",
1032
+ "method": "get",
1033
+ "toolName": "get-channel-message-hosted-content",
1034
+ "workScopes": ["ChannelMessage.Read.All"],
1035
+ "returnDownloadUrl": true,
1036
+ "llmTip": "Returns raw bytes of a hosted content item attached to a Teams channel message. Use list-channel-message-hosted-contents to discover IDs."
1037
+ },
1008
1038
  {
1009
1039
  "pathPattern": "/teams/{team-id}/channels/{channel-id}/messages",
1010
1040
  "method": "post",
@@ -1375,5 +1405,40 @@
1375
1405
  "toolName": "list-webinar-sessions",
1376
1406
  "workScopes": ["VirtualEvent.Read"],
1377
1407
  "llmTip": "Lists sessions for a webinar. Each session has startDateTime, endDateTime, joinWebUrl, subject, and is essentially an online meeting associated with the webinar."
1408
+ },
1409
+ {
1410
+ "pathPattern": "/places/{place-id}/graph.room",
1411
+ "method": "get",
1412
+ "toolName": "get-room",
1413
+ "workScopes": ["Place.Read.All"],
1414
+ "llmTip": "Gets a place cast as a room, returning room-specific properties: displayName, emailAddress (for booking), capacity, building, floorNumber, floorLabel, isWheelChairAccessible, audioDeviceName, videoDeviceName, displayDeviceName. The place-id can be the room's ID or email address."
1415
+ },
1416
+ {
1417
+ "pathPattern": "/places/{place-id}/graph.roomList",
1418
+ "method": "get",
1419
+ "toolName": "get-room-list",
1420
+ "workScopes": ["Place.Read.All"],
1421
+ "llmTip": "Gets a place cast as a room list, returning room list properties: displayName, emailAddress, address. Use the place-id (ID or email address) of the room list. Then use list-room-list-rooms to get the rooms within this list."
1422
+ },
1423
+ {
1424
+ "pathPattern": "/places/{place-id}/graph.roomList/rooms",
1425
+ "method": "get",
1426
+ "toolName": "list-room-list-rooms",
1427
+ "workScopes": ["Place.Read.All"],
1428
+ "llmTip": "Lists rooms belonging to a specific room list. The place-id is the ID or email address of the room list (from get-room-list). Returns rooms with displayName, emailAddress, capacity, building, floorNumber, floorLabel, and AV equipment details. Combine with find-meeting-times to find available rooms for booking."
1429
+ },
1430
+ {
1431
+ "pathPattern": "/places/{place-id}/graph.roomList/rooms/{room-id}",
1432
+ "method": "get",
1433
+ "toolName": "get-room-list-room",
1434
+ "workScopes": ["Place.Read.All"],
1435
+ "llmTip": "Gets a specific room within a room list. The place-id is the room list ID or email, and room-id is the specific room ID. Returns full room details including capacity, building, floor, and AV equipment."
1436
+ },
1437
+ {
1438
+ "pathPattern": "/places/{place-id}",
1439
+ "method": "patch",
1440
+ "toolName": "update-place",
1441
+ "workScopes": ["Place.ReadWrite.All"],
1442
+ "llmTip": "Updates properties of a place (room, room list, building, floor, section, desk, workspace). Body can include: displayName, phone, capacity, building, floorNumber, floorLabel, tags, audioDeviceName, videoDeviceName, displayDeviceName, isWheelChairAccessible. Use get-room or get-room-list to verify current values before updating."
1378
1443
  }
1379
1444
  ]
@@ -422,6 +422,11 @@ const microsoft_graph_chatMessageCollectionResponse = z.object({
422
422
  "@odata.nextLink": z.string().nullable(),
423
423
  value: z.array(microsoft_graph_chatMessage)
424
424
  }).partial().passthrough();
425
+ const microsoft_graph_chatMessageHostedContentCollectionResponse = z.object({
426
+ "@odata.count": z.number().int().nullable(),
427
+ "@odata.nextLink": z.string().nullable(),
428
+ value: z.array(microsoft_graph_chatMessageHostedContent)
429
+ }).partial().passthrough();
425
430
  const microsoft_graph_pinnedChatMessageInfoCollectionResponse = z.object({
426
431
  "@odata.count": z.number().int().nullable(),
427
432
  "@odata.nextLink": z.string().nullable(),
@@ -3593,6 +3598,120 @@ const microsoft_graph_linkedResourceCollectionResponse = z.object({
3593
3598
  "@odata.nextLink": z.string().nullable(),
3594
3599
  value: z.array(microsoft_graph_linkedResource)
3595
3600
  }).partial().passthrough();
3601
+ const microsoft_graph_checkInMethod = z.enum([
3602
+ "unspecified",
3603
+ "manual",
3604
+ "inferred",
3605
+ "verified",
3606
+ "unknownFutureValue"
3607
+ ]);
3608
+ const microsoft_graph_checkInClaim = z.object({
3609
+ calendarEventId: z.string().describe(
3610
+ "The unique identifier for an Outlook calendar event associated with the checkInClaim object. For more information, see the iCalUId property in event."
3611
+ ).optional(),
3612
+ checkInMethod: microsoft_graph_checkInMethod.optional(),
3613
+ createdDateTime: z.string().regex(
3614
+ /^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$/
3615
+ ).datetime({ offset: true }).describe(
3616
+ "The date and time when the checkInClaim object was created. The timestamp type represents date and time information using ISO 8601 format and is always in UTC. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z."
3617
+ ).nullish()
3618
+ }).passthrough();
3619
+ const microsoft_graph_place = z.object({
3620
+ id: z.string().describe("The unique identifier for an entity. Read-only.").optional(),
3621
+ address: microsoft_graph_physicalAddress.optional(),
3622
+ displayName: z.string().describe("The name that is associated with the place.").optional(),
3623
+ geoCoordinates: microsoft_graph_outlookGeoCoordinates.optional(),
3624
+ isWheelChairAccessible: z.boolean().describe("Indicates whether the place is wheelchair accessible.").nullish(),
3625
+ label: z.string().describe("User-defined description of the place.").nullish(),
3626
+ parentId: z.string().describe("The ID of a parent place.").nullish(),
3627
+ phone: z.string().describe("The phone number of the place.").nullish(),
3628
+ tags: z.array(z.string()).describe("Custom tags that are associated with the place for categorization or filtering.").optional(),
3629
+ checkIns: z.array(microsoft_graph_checkInClaim).describe(
3630
+ "A subresource of a place object that indicates the check-in status of an Outlook calendar event booked at the place."
3631
+ ).optional()
3632
+ }).passthrough();
3633
+ const microsoft_graph_bookingType = z.enum(["unknown", "standard", "reserved"]);
3634
+ const microsoft_graph_placeFeatureEnablement = z.enum([
3635
+ "unknown",
3636
+ "enabled",
3637
+ "disabled",
3638
+ "unknownFutureValue"
3639
+ ]);
3640
+ const microsoft_graph_room = z.object({
3641
+ id: z.string().describe("The unique identifier for an entity. Read-only.").optional(),
3642
+ address: microsoft_graph_physicalAddress.optional(),
3643
+ displayName: z.string().describe("The name that is associated with the place.").optional(),
3644
+ geoCoordinates: microsoft_graph_outlookGeoCoordinates.optional(),
3645
+ isWheelChairAccessible: z.boolean().describe("Indicates whether the place is wheelchair accessible.").nullish(),
3646
+ label: z.string().describe("User-defined description of the place.").nullish(),
3647
+ parentId: z.string().describe("The ID of a parent place.").nullish(),
3648
+ phone: z.string().describe("The phone number of the place.").nullish(),
3649
+ tags: z.array(z.string()).describe("Custom tags that are associated with the place for categorization or filtering.").optional(),
3650
+ checkIns: z.array(microsoft_graph_checkInClaim).describe(
3651
+ "A subresource of a place object that indicates the check-in status of an Outlook calendar event booked at the place."
3652
+ ).optional(),
3653
+ audioDeviceName: z.string().describe("Specifies the name of the audio device in the room.").nullish(),
3654
+ bookingType: microsoft_graph_bookingType.optional(),
3655
+ building: z.string().describe("Specifies the building name or building number that the room is in.").nullish(),
3656
+ capacity: z.number().gte(-2147483648).lte(2147483647).describe("Specifies the capacity of the room.").nullish(),
3657
+ displayDeviceName: z.string().describe("Specifies the name of the display device in the room.").nullish(),
3658
+ emailAddress: z.string().describe("Email address of the room.").nullish(),
3659
+ floorLabel: z.string().describe("Specifies a descriptive label for the floor, for example, P.").nullish(),
3660
+ floorNumber: z.number().gte(-2147483648).lte(2147483647).describe("Specifies the floor number that the room is on.").nullish(),
3661
+ nickname: z.string().describe("Specifies a nickname for the room, for example, 'conf room'.").optional(),
3662
+ placeId: z.string().describe("An alternative immutable unique identifier of the room. Read-only.").nullish(),
3663
+ teamsEnabledState: microsoft_graph_placeFeatureEnablement.optional(),
3664
+ videoDeviceName: z.string().describe("Specifies the name of the video device in the room.").nullish()
3665
+ }).passthrough();
3666
+ const microsoft_graph_placeMode = z.object({}).passthrough();
3667
+ const microsoft_graph_workspace = z.object({
3668
+ id: z.string().describe("The unique identifier for an entity. Read-only.").optional(),
3669
+ address: microsoft_graph_physicalAddress.optional(),
3670
+ displayName: z.string().describe("The name that is associated with the place.").optional(),
3671
+ geoCoordinates: microsoft_graph_outlookGeoCoordinates.optional(),
3672
+ isWheelChairAccessible: z.boolean().describe("Indicates whether the place is wheelchair accessible.").nullish(),
3673
+ label: z.string().describe("User-defined description of the place.").nullish(),
3674
+ parentId: z.string().describe("The ID of a parent place.").nullish(),
3675
+ phone: z.string().describe("The phone number of the place.").nullish(),
3676
+ tags: z.array(z.string()).describe("Custom tags that are associated with the place for categorization or filtering.").optional(),
3677
+ checkIns: z.array(microsoft_graph_checkInClaim).describe(
3678
+ "A subresource of a place object that indicates the check-in status of an Outlook calendar event booked at the place."
3679
+ ).optional(),
3680
+ capacity: z.number().gte(-2147483648).lte(2147483647).describe("The maximum number of individual desks within a workspace.").nullish(),
3681
+ displayDeviceName: z.string().describe(
3682
+ "The name of the display device (for example, monitor or projector) that is available in the workspace."
3683
+ ).nullish(),
3684
+ emailAddress: z.string().describe(
3685
+ "The email address that is associated with the workspace. This email address is used for booking."
3686
+ ).nullish(),
3687
+ mode: microsoft_graph_placeMode.optional(),
3688
+ nickname: z.string().describe(
3689
+ "A short, friendly name for the workspace, often used for easier identification or display in the UI."
3690
+ ).optional(),
3691
+ placeId: z.string().describe("An alternative immutable unique identifier of the workspace. Read-only.").nullish()
3692
+ }).passthrough();
3693
+ const microsoft_graph_roomList = z.object({
3694
+ id: z.string().describe("The unique identifier for an entity. Read-only.").optional(),
3695
+ address: microsoft_graph_physicalAddress.optional(),
3696
+ displayName: z.string().describe("The name that is associated with the place.").optional(),
3697
+ geoCoordinates: microsoft_graph_outlookGeoCoordinates.optional(),
3698
+ isWheelChairAccessible: z.boolean().describe("Indicates whether the place is wheelchair accessible.").nullish(),
3699
+ label: z.string().describe("User-defined description of the place.").nullish(),
3700
+ parentId: z.string().describe("The ID of a parent place.").nullish(),
3701
+ phone: z.string().describe("The phone number of the place.").nullish(),
3702
+ tags: z.array(z.string()).describe("Custom tags that are associated with the place for categorization or filtering.").optional(),
3703
+ checkIns: z.array(microsoft_graph_checkInClaim).describe(
3704
+ "A subresource of a place object that indicates the check-in status of an Outlook calendar event booked at the place."
3705
+ ).optional(),
3706
+ emailAddress: z.string().describe("The email address of the room list.").nullish(),
3707
+ rooms: z.array(microsoft_graph_room).optional(),
3708
+ workspaces: z.array(microsoft_graph_workspace).optional()
3709
+ }).passthrough();
3710
+ const microsoft_graph_roomCollectionResponse = z.object({
3711
+ "@odata.count": z.number().int().nullable(),
3712
+ "@odata.nextLink": z.string().nullable(),
3713
+ value: z.array(microsoft_graph_room)
3714
+ }).partial().passthrough();
3596
3715
  const microsoft_graph_plannerContainerType = z.enum(["group", "unknownFutureValue", "roster"]);
3597
3716
  const microsoft_graph_plannerPlanContainer = z.object({
3598
3717
  containerId: z.string().describe("The identifier of the resource that contains the plan. Optional.").nullish(),
@@ -4189,6 +4308,7 @@ const schemas = {
4189
4308
  microsoft_graph_ODataErrors_ODataError,
4190
4309
  microsoft_graph_conversationMemberCollectionResponse,
4191
4310
  microsoft_graph_chatMessageCollectionResponse,
4311
+ microsoft_graph_chatMessageHostedContentCollectionResponse,
4192
4312
  microsoft_graph_pinnedChatMessageInfoCollectionResponse,
4193
4313
  microsoft_graph_outOfOfficeSettings,
4194
4314
  microsoft_graph_dateTimeTimeZone,
@@ -4497,6 +4617,16 @@ const schemas = {
4497
4617
  microsoft_graph_todoTaskListCollectionResponse,
4498
4618
  microsoft_graph_todoTaskCollectionResponse,
4499
4619
  microsoft_graph_linkedResourceCollectionResponse,
4620
+ microsoft_graph_checkInMethod,
4621
+ microsoft_graph_checkInClaim,
4622
+ microsoft_graph_place,
4623
+ microsoft_graph_bookingType,
4624
+ microsoft_graph_placeFeatureEnablement,
4625
+ microsoft_graph_room,
4626
+ microsoft_graph_placeMode,
4627
+ microsoft_graph_workspace,
4628
+ microsoft_graph_roomList,
4629
+ microsoft_graph_roomCollectionResponse,
4500
4630
  microsoft_graph_plannerContainerType,
4501
4631
  microsoft_graph_plannerPlanContainer,
4502
4632
  microsoft_graph_plannerBucket,
@@ -4716,6 +4846,64 @@ const endpoints = makeApi([
4716
4846
  ],
4717
4847
  response: z.void()
4718
4848
  },
4849
+ {
4850
+ method: "get",
4851
+ path: "/chats/:chatId/messages/:chatMessageId/hostedContents",
4852
+ alias: "list-chat-message-hosted-contents",
4853
+ description: `Retrieve the list of chatMessageHostedContent objects from a message. This API only lists the hosted content objects. To get the content bytes, see get chatmessage hosted content.`,
4854
+ requestFormat: "json",
4855
+ parameters: [
4856
+ {
4857
+ name: "$top",
4858
+ type: "Query",
4859
+ schema: z.number().int().gte(0).describe("Show only the first n items").optional()
4860
+ },
4861
+ {
4862
+ name: "$skip",
4863
+ type: "Query",
4864
+ schema: z.number().int().gte(0).describe("Skip the first n items").optional()
4865
+ },
4866
+ {
4867
+ name: "$search",
4868
+ type: "Query",
4869
+ schema: z.string().describe("Search items by search phrases").optional()
4870
+ },
4871
+ {
4872
+ name: "$filter",
4873
+ type: "Query",
4874
+ schema: z.string().describe("Filter items by property values").optional()
4875
+ },
4876
+ {
4877
+ name: "$count",
4878
+ type: "Query",
4879
+ schema: z.boolean().describe("Include count of items").optional()
4880
+ },
4881
+ {
4882
+ name: "$orderby",
4883
+ type: "Query",
4884
+ schema: z.array(z.string()).describe("Order items by property values").optional()
4885
+ },
4886
+ {
4887
+ name: "$select",
4888
+ type: "Query",
4889
+ schema: z.array(z.string()).describe("Select properties to be returned").optional()
4890
+ },
4891
+ {
4892
+ name: "$expand",
4893
+ type: "Query",
4894
+ schema: z.array(z.string()).describe("Expand related entities").optional()
4895
+ }
4896
+ ],
4897
+ response: z.void()
4898
+ },
4899
+ {
4900
+ method: "get",
4901
+ path: "/chats/:chatId/messages/:chatMessageId/hostedContents/:chatMessageHostedContentId/$value",
4902
+ alias: "get-chat-message-hosted-content",
4903
+ description: `Retrieve the list of chatMessageHostedContent objects from a message. This API only lists the hosted content objects. To get the content bytes, see get chatmessage hosted content.`,
4904
+ requestFormat: "json",
4905
+ response: z.void()
4906
+ },
4719
4907
  {
4720
4908
  method: "get",
4721
4909
  path: "/chats/:chatId/messages/:chatMessageId/replies",
@@ -9271,6 +9459,141 @@ For example, if the user uploads a photo that is 504x504 pixels, all but the 648
9271
9459
  ],
9272
9460
  response: z.void()
9273
9461
  },
9462
+ {
9463
+ method: "patch",
9464
+ path: "/places/:placeId",
9465
+ alias: "update-place",
9466
+ description: `Update the properties of place object that can be a building, floor, section, desk, room, workspace, or roomList. You can identify the place by specifying the id property.`,
9467
+ requestFormat: "json",
9468
+ parameters: [
9469
+ {
9470
+ name: "body",
9471
+ description: `New property values`,
9472
+ type: "Body",
9473
+ schema: microsoft_graph_place
9474
+ }
9475
+ ],
9476
+ response: z.void()
9477
+ },
9478
+ {
9479
+ method: "get",
9480
+ path: "/places/:placeId/graph.room",
9481
+ alias: "get-room",
9482
+ description: `Get a collection of the specified type of place objects defined in a tenant. You can do the following for a given tenant:
9483
+ - List all buildings.
9484
+ - List all floors.
9485
+ - List all sections.
9486
+ - List all desks.
9487
+ - List all rooms.
9488
+ - List all workspaces.
9489
+ - List all room lists.
9490
+ - List rooms in a specific room list.
9491
+ - List workspaces in a specific room list.`,
9492
+ requestFormat: "json",
9493
+ parameters: [
9494
+ {
9495
+ name: "$select",
9496
+ type: "Query",
9497
+ schema: z.array(z.string()).describe("Select properties to be returned").optional()
9498
+ },
9499
+ {
9500
+ name: "$expand",
9501
+ type: "Query",
9502
+ schema: z.array(z.string()).describe("Expand related entities").optional()
9503
+ }
9504
+ ],
9505
+ response: z.void()
9506
+ },
9507
+ {
9508
+ method: "get",
9509
+ path: "/places/:placeId/graph.roomList",
9510
+ alias: "get-room-list",
9511
+ description: `Read the properties of a place object specified by its ID. The place object can be one of the following types: The listed resources are derived from the place object.`,
9512
+ requestFormat: "json",
9513
+ parameters: [
9514
+ {
9515
+ name: "$select",
9516
+ type: "Query",
9517
+ schema: z.array(z.string()).describe("Select properties to be returned").optional()
9518
+ },
9519
+ {
9520
+ name: "$expand",
9521
+ type: "Query",
9522
+ schema: z.array(z.string()).describe("Expand related entities").optional()
9523
+ }
9524
+ ],
9525
+ response: z.void()
9526
+ },
9527
+ {
9528
+ method: "get",
9529
+ path: "/places/:placeId/graph.roomList/rooms",
9530
+ alias: "list-room-list-rooms",
9531
+ description: `Get rooms from places`,
9532
+ requestFormat: "json",
9533
+ parameters: [
9534
+ {
9535
+ name: "$top",
9536
+ type: "Query",
9537
+ schema: z.number().int().gte(0).describe("Show only the first n items").optional()
9538
+ },
9539
+ {
9540
+ name: "$skip",
9541
+ type: "Query",
9542
+ schema: z.number().int().gte(0).describe("Skip the first n items").optional()
9543
+ },
9544
+ {
9545
+ name: "$search",
9546
+ type: "Query",
9547
+ schema: z.string().describe("Search items by search phrases").optional()
9548
+ },
9549
+ {
9550
+ name: "$filter",
9551
+ type: "Query",
9552
+ schema: z.string().describe("Filter items by property values").optional()
9553
+ },
9554
+ {
9555
+ name: "$count",
9556
+ type: "Query",
9557
+ schema: z.boolean().describe("Include count of items").optional()
9558
+ },
9559
+ {
9560
+ name: "$orderby",
9561
+ type: "Query",
9562
+ schema: z.array(z.string()).describe("Order items by property values").optional()
9563
+ },
9564
+ {
9565
+ name: "$select",
9566
+ type: "Query",
9567
+ schema: z.array(z.string()).describe("Select properties to be returned").optional()
9568
+ },
9569
+ {
9570
+ name: "$expand",
9571
+ type: "Query",
9572
+ schema: z.array(z.string()).describe("Expand related entities").optional()
9573
+ }
9574
+ ],
9575
+ response: z.void()
9576
+ },
9577
+ {
9578
+ method: "get",
9579
+ path: "/places/:placeId/graph.roomList/rooms/:roomId",
9580
+ alias: "get-room-list-room",
9581
+ description: `Get rooms from places`,
9582
+ requestFormat: "json",
9583
+ parameters: [
9584
+ {
9585
+ name: "$select",
9586
+ type: "Query",
9587
+ schema: z.array(z.string()).describe("Select properties to be returned").optional()
9588
+ },
9589
+ {
9590
+ name: "$expand",
9591
+ type: "Query",
9592
+ schema: z.array(z.string()).describe("Expand related entities").optional()
9593
+ }
9594
+ ],
9595
+ response: z.void()
9596
+ },
9274
9597
  {
9275
9598
  method: "get",
9276
9599
  path: "/planner/plans/:plannerPlanId",
@@ -10349,6 +10672,64 @@ To monitor future changes, call the delta API by using the @odata.deltaLink in t
10349
10672
  ],
10350
10673
  response: z.void()
10351
10674
  },
10675
+ {
10676
+ method: "get",
10677
+ path: "/teams/:teamId/channels/:channelId/messages/:chatMessageId/hostedContents",
10678
+ alias: "list-channel-message-hosted-contents",
10679
+ description: `Retrieve the list of chatMessageHostedContent objects from a message. This API only lists the hosted content objects. To get the content bytes, see get chatmessage hosted content.`,
10680
+ requestFormat: "json",
10681
+ parameters: [
10682
+ {
10683
+ name: "$top",
10684
+ type: "Query",
10685
+ schema: z.number().int().gte(0).describe("Show only the first n items").optional()
10686
+ },
10687
+ {
10688
+ name: "$skip",
10689
+ type: "Query",
10690
+ schema: z.number().int().gte(0).describe("Skip the first n items").optional()
10691
+ },
10692
+ {
10693
+ name: "$search",
10694
+ type: "Query",
10695
+ schema: z.string().describe("Search items by search phrases").optional()
10696
+ },
10697
+ {
10698
+ name: "$filter",
10699
+ type: "Query",
10700
+ schema: z.string().describe("Filter items by property values").optional()
10701
+ },
10702
+ {
10703
+ name: "$count",
10704
+ type: "Query",
10705
+ schema: z.boolean().describe("Include count of items").optional()
10706
+ },
10707
+ {
10708
+ name: "$orderby",
10709
+ type: "Query",
10710
+ schema: z.array(z.string()).describe("Order items by property values").optional()
10711
+ },
10712
+ {
10713
+ name: "$select",
10714
+ type: "Query",
10715
+ schema: z.array(z.string()).describe("Select properties to be returned").optional()
10716
+ },
10717
+ {
10718
+ name: "$expand",
10719
+ type: "Query",
10720
+ schema: z.array(z.string()).describe("Expand related entities").optional()
10721
+ }
10722
+ ],
10723
+ response: z.void()
10724
+ },
10725
+ {
10726
+ method: "get",
10727
+ path: "/teams/:teamId/channels/:channelId/messages/:chatMessageId/hostedContents/:chatMessageHostedContentId/$value",
10728
+ alias: "get-channel-message-hosted-content",
10729
+ description: `Retrieve the list of chatMessageHostedContent objects from a message. This API only lists the hosted content objects. To get the content bytes, see get chatmessage hosted content.`,
10730
+ requestFormat: "json",
10731
+ response: z.void()
10732
+ },
10352
10733
  {
10353
10734
  method: "get",
10354
10735
  path: "/teams/:teamId/channels/:channelId/messages/:chatMessageId/replies",
@@ -3,6 +3,27 @@ import { refreshAccessToken } from "./lib/microsoft-auth.js";
3
3
  import { encode as toonEncode } from "@toon-format/toon";
4
4
  import { getCloudEndpoints } from "./cloud-config.js";
5
5
  import { getRequestTokens } from "./request-context.js";
6
+ function isBinaryContentType(contentType) {
7
+ if (!contentType) return false;
8
+ const lower = contentType.toLowerCase().split(";")[0].trim();
9
+ if (!lower) return false;
10
+ if (lower.startsWith("image/") || lower.startsWith("video/") || lower.startsWith("audio/") || lower.startsWith("font/")) {
11
+ return true;
12
+ }
13
+ if (lower === "application/octet-stream" || lower === "application/pdf") {
14
+ return true;
15
+ }
16
+ if (lower.startsWith("application/zip") || lower.startsWith("application/x-zip")) {
17
+ return true;
18
+ }
19
+ if (lower.startsWith("application/vnd.") || lower.startsWith("application/x-")) {
20
+ if (lower.endsWith("+json") || lower.endsWith("+xml") || lower.endsWith("+text")) {
21
+ return false;
22
+ }
23
+ return true;
24
+ }
25
+ return false;
26
+ }
6
27
  class GraphClient {
7
28
  constructor(authManager, secrets, outputFormat = "json") {
8
29
  this.outputFormat = "json";
@@ -40,15 +61,28 @@ class GraphClient {
40
61
  `Microsoft Graph API error: ${response.status} ${response.statusText} - ${await response.text()}`
41
62
  );
42
63
  }
43
- const text = await response.text();
64
+ const contentTypeHeader = response.headers?.get?.("content-type") || "";
65
+ const isBinaryResponse = isBinaryContentType(contentTypeHeader);
44
66
  let result;
45
- if (text === "") {
46
- result = { message: "OK!" };
67
+ if (isBinaryResponse) {
68
+ const buffer = Buffer.from(await response.arrayBuffer());
69
+ result = {
70
+ message: "OK!",
71
+ contentType: contentTypeHeader,
72
+ encoding: "base64",
73
+ contentLength: buffer.byteLength,
74
+ contentBytes: buffer.toString("base64")
75
+ };
47
76
  } else {
48
- try {
49
- result = JSON.parse(text);
50
- } catch {
51
- result = { message: "OK!", rawResponse: text };
77
+ const text = await response.text();
78
+ if (text === "") {
79
+ result = { message: "OK!" };
80
+ } else {
81
+ try {
82
+ result = JSON.parse(text);
83
+ } catch {
84
+ result = { message: "OK!", rawResponse: text };
85
+ }
52
86
  }
53
87
  }
54
88
  if (options.includeHeaders) {
@@ -205,5 +239,6 @@ class GraphClient {
205
239
  }
206
240
  var graph_client_default = GraphClient;
207
241
  export {
208
- graph_client_default as default
242
+ graph_client_default as default,
243
+ isBinaryContentType
209
244
  };
@@ -0,0 +1,25 @@
1
+ function buildGeneralMcpInstructions(opts) {
2
+ const parts = [
3
+ "Microsoft 365 MCP exposes Microsoft Graph through MCP tools. Use each tool name, description, and parameter schema as the source of truth.",
4
+ "Microsoft Graph OData: do not combine $filter with $search on the same request. For lists, prefer modest $top (or top) and $select; avoid very large pages unless the user needs them.",
5
+ "Mail and message $search uses KQL; the $search query parameter value must be double-quoted per Graph (see search-query-parameter in Microsoft Graph docs).",
6
+ "When you need an organizational user or recipient address, resolve it with list-users (or another directory tool); do not invent SMTP addresses.",
7
+ "Directory $search on collections such as /users or /groups requires ConsistencyLevel: eventual when the tool exposes that header.",
8
+ "Teams chat and channel messages: prefer HTML contentType in the body; plain text is often mangled by Graph."
9
+ ];
10
+ if (opts.readOnly) parts.push("This server is read-only; write operations are disabled.");
11
+ if (opts.multiAccount)
12
+ parts.push("Multiple accounts: pass the account parameter when required (see list-accounts).");
13
+ if (!opts.orgMode)
14
+ parts.push("Work/school-only tools require starting the server with --org-mode.");
15
+ return parts.join(" ");
16
+ }
17
+ const DISCOVERY_MODE_INSTRUCTIONS_ADDON = "DISCOVERY MODE ADD-ON: Graph is reached via search-tools then execute-tool (plus auth helpers). Call search-tools with short keywords, then execute-tool with tool_name exactly as returned; put Graph parameters in the parameters object. If search-tools returns no matches, retry with shorter or different keywords.";
18
+ function buildMcpServerInstructions(opts) {
19
+ const general = buildGeneralMcpInstructions(opts);
20
+ if (!opts.discovery) return general;
21
+ return `${general} ${DISCOVERY_MODE_INSTRUCTIONS_ADDON}`;
22
+ }
23
+ export {
24
+ buildMcpServerInstructions
25
+ };
package/dist/server.js CHANGED
@@ -6,6 +6,7 @@ import express from "express";
6
6
  import logger, { enableConsoleLogging } from "./logger.js";
7
7
  import { registerAuthTools } from "./auth-tools.js";
8
8
  import { registerGraphTools, registerDiscoveryTools } from "./graph-tools.js";
9
+ import { buildMcpServerInstructions } from "./mcp-instructions.js";
9
10
  import GraphClient from "./graph-client.js";
10
11
  import { buildScopesFromEndpoints } from "./auth.js";
11
12
  import { MicrosoftOAuthProvider } from "./oauth-provider.js";
@@ -46,10 +47,20 @@ class MicrosoftGraphServer {
46
47
  this.secrets = null;
47
48
  }
48
49
  createMcpServer() {
49
- const server = new McpServer({
50
- name: "Microsoft365MCP",
51
- version: this.version
52
- });
50
+ const server = new McpServer(
51
+ {
52
+ name: "Microsoft365MCP",
53
+ version: this.version
54
+ },
55
+ {
56
+ instructions: buildMcpServerInstructions({
57
+ discovery: Boolean(this.options.discovery),
58
+ orgMode: Boolean(this.options.orgMode),
59
+ readOnly: Boolean(this.options.readOnly),
60
+ multiAccount: this.multiAccount
61
+ })
62
+ }
63
+ );
53
64
  const shouldRegisterAuthTools = !this.options.http || this.options.enableAuthTools;
54
65
  if (shouldRegisterAuthTools) {
55
66
  registerAuthTools(server, this.authManager);
@@ -1,10 +1,11 @@
1
- 2026-04-13 16:18:48 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
2
- 2026-04-13 16:18:49 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
3
- 2026-04-13 16:18:49 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
4
- 2026-04-13 16:18:49 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me/messages
5
- 2026-04-13 16:18:49 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me/calendar
6
- 2026-04-13 16:18:50 INFO: Using environment variables for secrets
7
- 2026-04-13 16:18:50 INFO: Using environment variables for secrets
8
- 2026-04-13 16:18:50 INFO: Using environment variables for secrets
9
- 2026-04-13 16:18:50 INFO: Using environment variables for secrets
10
- 2026-04-13 16:18:50 INFO: Using environment variables for secrets
1
+ 2026-04-14 20:54:17 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
2
+ 2026-04-14 20:54:17 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
3
+ 2026-04-14 20:54:17 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
4
+ 2026-04-14 20:54:17 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me/messages
5
+ 2026-04-14 20:54:17 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me/calendar
6
+ 2026-04-14 20:54:17 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me/photo/$value
7
+ 2026-04-14 20:54:18 INFO: Using environment variables for secrets
8
+ 2026-04-14 20:54:18 INFO: Using environment variables for secrets
9
+ 2026-04-14 20:54:18 INFO: Using environment variables for secrets
10
+ 2026-04-14 20:54:18 INFO: Using environment variables for secrets
11
+ 2026-04-14 20:54:18 INFO: Using environment variables for secrets
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softeria/ms-365-mcp-server",
3
- "version": "0.76.0",
3
+ "version": "0.78.0",
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",
@@ -944,6 +944,21 @@
944
944
  "toolName": "get-chat-message",
945
945
  "workScopes": ["ChatMessage.Read"]
946
946
  },
947
+ {
948
+ "pathPattern": "/chats/{chat-id}/messages/{chatMessage-id}/hostedContents",
949
+ "method": "get",
950
+ "toolName": "list-chat-message-hosted-contents",
951
+ "workScopes": ["ChatMessage.Read"],
952
+ "llmTip": "Lists hosted-content references (inline images, code snippets) attached to a Teams chat message. Returns an array of { id, contentType }. Use get-chat-message-hosted-content with the id to download the bytes. Hosted content IDs can also be parsed from the <img src> URL in the message body between /hostedContents/ and /$value."
953
+ },
954
+ {
955
+ "pathPattern": "/chats/{chat-id}/messages/{chatMessage-id}/hostedContents/{chatMessageHostedContent-id}/$value",
956
+ "method": "get",
957
+ "toolName": "get-chat-message-hosted-content",
958
+ "workScopes": ["ChatMessage.Read"],
959
+ "returnDownloadUrl": true,
960
+ "llmTip": "Returns raw bytes of a hosted content item (typically image/png or image/jpeg) attached to a Teams 1:1 or group chat message. Use list-chat-message-hosted-contents to discover IDs, or extract the ID from the <img src> URL in the message body."
961
+ },
947
962
  {
948
963
  "pathPattern": "/chats/{chat-id}/messages",
949
964
  "method": "post",
@@ -1005,6 +1020,21 @@
1005
1020
  "toolName": "get-channel-message",
1006
1021
  "workScopes": ["ChannelMessage.Read.All"]
1007
1022
  },
1023
+ {
1024
+ "pathPattern": "/teams/{team-id}/channels/{channel-id}/messages/{chatMessage-id}/hostedContents",
1025
+ "method": "get",
1026
+ "toolName": "list-channel-message-hosted-contents",
1027
+ "workScopes": ["ChannelMessage.Read.All"],
1028
+ "llmTip": "Lists hosted-content references (inline images, code snippets) attached to a Teams channel message. Returns an array of { id, contentType }. Use get-channel-message-hosted-content with the id to download bytes."
1029
+ },
1030
+ {
1031
+ "pathPattern": "/teams/{team-id}/channels/{channel-id}/messages/{chatMessage-id}/hostedContents/{chatMessageHostedContent-id}/$value",
1032
+ "method": "get",
1033
+ "toolName": "get-channel-message-hosted-content",
1034
+ "workScopes": ["ChannelMessage.Read.All"],
1035
+ "returnDownloadUrl": true,
1036
+ "llmTip": "Returns raw bytes of a hosted content item attached to a Teams channel message. Use list-channel-message-hosted-contents to discover IDs."
1037
+ },
1008
1038
  {
1009
1039
  "pathPattern": "/teams/{team-id}/channels/{channel-id}/messages",
1010
1040
  "method": "post",
@@ -1375,5 +1405,40 @@
1375
1405
  "toolName": "list-webinar-sessions",
1376
1406
  "workScopes": ["VirtualEvent.Read"],
1377
1407
  "llmTip": "Lists sessions for a webinar. Each session has startDateTime, endDateTime, joinWebUrl, subject, and is essentially an online meeting associated with the webinar."
1408
+ },
1409
+ {
1410
+ "pathPattern": "/places/{place-id}/graph.room",
1411
+ "method": "get",
1412
+ "toolName": "get-room",
1413
+ "workScopes": ["Place.Read.All"],
1414
+ "llmTip": "Gets a place cast as a room, returning room-specific properties: displayName, emailAddress (for booking), capacity, building, floorNumber, floorLabel, isWheelChairAccessible, audioDeviceName, videoDeviceName, displayDeviceName. The place-id can be the room's ID or email address."
1415
+ },
1416
+ {
1417
+ "pathPattern": "/places/{place-id}/graph.roomList",
1418
+ "method": "get",
1419
+ "toolName": "get-room-list",
1420
+ "workScopes": ["Place.Read.All"],
1421
+ "llmTip": "Gets a place cast as a room list, returning room list properties: displayName, emailAddress, address. Use the place-id (ID or email address) of the room list. Then use list-room-list-rooms to get the rooms within this list."
1422
+ },
1423
+ {
1424
+ "pathPattern": "/places/{place-id}/graph.roomList/rooms",
1425
+ "method": "get",
1426
+ "toolName": "list-room-list-rooms",
1427
+ "workScopes": ["Place.Read.All"],
1428
+ "llmTip": "Lists rooms belonging to a specific room list. The place-id is the ID or email address of the room list (from get-room-list). Returns rooms with displayName, emailAddress, capacity, building, floorNumber, floorLabel, and AV equipment details. Combine with find-meeting-times to find available rooms for booking."
1429
+ },
1430
+ {
1431
+ "pathPattern": "/places/{place-id}/graph.roomList/rooms/{room-id}",
1432
+ "method": "get",
1433
+ "toolName": "get-room-list-room",
1434
+ "workScopes": ["Place.Read.All"],
1435
+ "llmTip": "Gets a specific room within a room list. The place-id is the room list ID or email, and room-id is the specific room ID. Returns full room details including capacity, building, floor, and AV equipment."
1436
+ },
1437
+ {
1438
+ "pathPattern": "/places/{place-id}",
1439
+ "method": "patch",
1440
+ "toolName": "update-place",
1441
+ "workScopes": ["Place.ReadWrite.All"],
1442
+ "llmTip": "Updates properties of a place (room, room list, building, floor, section, desk, workspace). Body can include: displayName, phone, capacity, building, floorNumber, floorLabel, tags, audioDeviceName, videoDeviceName, displayDeviceName, isWheelChairAccessible. Use get-room or get-room-list to verify current values before updating."
1378
1443
  }
1379
1444
  ]