msteams-mcp 0.26.0 → 0.27.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Teams MCP Server
1
+ # Teams MCP Server & CLI
2
2
 
3
3
  [![CI](https://github.com/m0nkmaster/msteams-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/m0nkmaster/msteams-mcp/actions/workflows/ci.yml)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -83,5 +83,10 @@ export declare function clearTokenCache(): void;
83
83
  /**
84
84
  * Gets the Teams origin from session state.
85
85
  * Checks multiple known Teams domains to support government clouds.
86
+ *
87
+ * Prefers an origin that has a SubstrateSearch token so Outlook/email and
88
+ * Substrate search keep working when both teams.cloud.microsoft and
89
+ * teams.microsoft.com are present in the saved session (common after the
90
+ * New Teams host migration).
86
91
  */
87
92
  export declare function getTeamsOrigin(state: SessionState): SessionState['origins'][number] | null;
@@ -208,18 +208,45 @@ export function clearTokenCache() {
208
208
  * Used to find the correct origin in session state.
209
209
  */
210
210
  const TEAMS_ORIGINS = [
211
- 'https://teams.microsoft.com', // Commercial
211
+ 'https://teams.cloud.microsoft', // New Teams URL (often holds SubstrateSearch tokens)
212
+ 'https://teams.microsoft.com', // Commercial legacy
212
213
  'https://teams.microsoft.us', // GCC-High
213
214
  'https://dod.teams.microsoft.us', // DoD
214
- 'https://teams.cloud.microsoft', // New Teams URL
215
215
  ];
216
+ /**
217
+ * Returns true if localStorage has a SubstrateSearch MSAL token entry.
218
+ */
219
+ function hasSubstrateSearchToken(localStorage) {
220
+ for (const item of localStorage ?? []) {
221
+ try {
222
+ const entry = JSON.parse(item.value);
223
+ if (entry.target?.includes('SubstrateSearch') &&
224
+ typeof entry.secret === 'string' &&
225
+ entry.secret.startsWith('ey')) {
226
+ return true;
227
+ }
228
+ }
229
+ catch {
230
+ // ignore non-JSON localStorage values
231
+ }
232
+ }
233
+ return false;
234
+ }
216
235
  /**
217
236
  * Gets the Teams origin from session state.
218
237
  * Checks multiple known Teams domains to support government clouds.
238
+ *
239
+ * Prefers an origin that has a SubstrateSearch token so Outlook/email and
240
+ * Substrate search keep working when both teams.cloud.microsoft and
241
+ * teams.microsoft.com are present in the saved session (common after the
242
+ * New Teams host migration).
219
243
  */
220
244
  export function getTeamsOrigin(state) {
221
245
  if (!state.origins)
222
246
  return null;
247
+ const withSubstrate = state.origins.find(o => hasSubstrateSearchToken(o.localStorage));
248
+ if (withSubstrate)
249
+ return withSubstrate;
223
250
  // Try known Teams origins in priority order
224
251
  for (const knownOrigin of TEAMS_ORIGINS) {
225
252
  const origin = state.origins.find(o => o.origin === knownOrigin);
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for getTeamsOrigin — especially New Teams (teams.cloud.microsoft)
3
+ * SubstrateSearch token selection when multiple origins are present.
4
+ */
5
+ export {};
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Tests for getTeamsOrigin — especially New Teams (teams.cloud.microsoft)
3
+ * SubstrateSearch token selection when multiple origins are present.
4
+ */
5
+ import { describe, it, expect } from 'vitest';
6
+ import { getTeamsOrigin } from './session-store.js';
7
+ function makeOrigin(origin, localStorage = []) {
8
+ return { origin, localStorage };
9
+ }
10
+ function makeSubstrateEntry(target = 'https://substrate.office.com/SubstrateSearch-Internal.ReadWrite') {
11
+ return {
12
+ name: 'msal-substrate-token',
13
+ value: JSON.stringify({
14
+ credentialType: 'AccessToken',
15
+ target,
16
+ // JWT-shaped secret (header.payload.sig) — extractor only checks prefix
17
+ secret: 'eyJhbGciOiJub25lIn0.eyJzdWIiOiJ0ZXN0In0.sig',
18
+ }),
19
+ };
20
+ }
21
+ function makeChatSvcEntry() {
22
+ return {
23
+ name: 'msal-chatsvc-token',
24
+ value: JSON.stringify({
25
+ credentialType: 'AccessToken',
26
+ target: 'https://chatsvcagg.teams.microsoft.com/.default',
27
+ secret: 'eyJhbGciOiJub25lIn0.eyJzdWIiOiJjaGF0In0.sig',
28
+ }),
29
+ };
30
+ }
31
+ describe('getTeamsOrigin', () => {
32
+ it('prefers the origin that holds a SubstrateSearch token', () => {
33
+ const state = {
34
+ cookies: [],
35
+ origins: [
36
+ makeOrigin('https://teams.microsoft.com', [makeChatSvcEntry()]),
37
+ makeOrigin('https://teams.cloud.microsoft', [makeSubstrateEntry()]),
38
+ ],
39
+ };
40
+ const chosen = getTeamsOrigin(state);
41
+ expect(chosen?.origin).toBe('https://teams.cloud.microsoft');
42
+ });
43
+ it('falls back to teams.cloud.microsoft when no Substrate token exists', () => {
44
+ const state = {
45
+ cookies: [],
46
+ origins: [
47
+ makeOrigin('https://teams.microsoft.com', [makeChatSvcEntry()]),
48
+ makeOrigin('https://teams.cloud.microsoft', [makeChatSvcEntry()]),
49
+ ],
50
+ };
51
+ const chosen = getTeamsOrigin(state);
52
+ expect(chosen?.origin).toBe('https://teams.cloud.microsoft');
53
+ });
54
+ it('returns teams.microsoft.com when it is the only known origin', () => {
55
+ const state = {
56
+ cookies: [],
57
+ origins: [makeOrigin('https://teams.microsoft.com', [makeChatSvcEntry()])],
58
+ };
59
+ const chosen = getTeamsOrigin(state);
60
+ expect(chosen?.origin).toBe('https://teams.microsoft.com');
61
+ });
62
+ it('returns null when no Teams origins are present', () => {
63
+ const state = {
64
+ cookies: [],
65
+ origins: [makeOrigin('https://login.microsoftonline.com', [])],
66
+ };
67
+ expect(getTeamsOrigin(state)).toBeNull();
68
+ });
69
+ });
package/dist/cli.js CHANGED
File without changes
package/dist/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "msteams-mcp",
3
- "version": "0.26.0",
3
+ "version": "0.27.0",
4
4
  "description": "MCP server for Microsoft Teams - search messages, send replies, manage favourites",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",