mcp-sharepoint-us 2.0.7__tar.gz → 2.0.10__tar.gz

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.

Potentially problematic release.


This version of mcp-sharepoint-us might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-sharepoint-us
3
- Version: 2.0.7
3
+ Version: 2.0.10
4
4
  Summary: SharePoint MCP Server with Modern Azure AD Authentication
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/mdev26/mcp-sharepoint-us
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mcp-sharepoint-us"
7
- version = "2.0.7"
7
+ version = "2.0.10"
8
8
  description = "SharePoint MCP Server with Modern Azure AD Authentication"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -505,24 +505,37 @@ async def get_tree(folder_path: str = "", max_depth: int = 5, current_depth: int
505
505
  """Get folder tree structure"""
506
506
  if current_depth >= max_depth:
507
507
  return [TextContent(type="text", text="Max depth reached")]
508
-
508
+
509
509
  try:
510
510
  doc_lib = get_document_library_path()
511
511
  full_path = f"{doc_lib}/{folder_path}" if folder_path else doc_lib
512
-
512
+
513
513
  folder = ctx.web.get_folder_by_server_relative_path(full_path)
514
514
  folders = folder.folders.get().execute_query()
515
-
515
+
516
516
  indent = " " * current_depth
517
517
  tree_lines = [f"{indent}📁 {folder_path or 'Root'}"]
518
-
518
+
519
519
  for f in folders:
520
520
  sub_path = f"{folder_path}/{f.name}" if folder_path else f.name
521
521
  sub_tree = await get_tree(sub_path, max_depth, current_depth + 1)
522
522
  tree_lines.append(sub_tree[0].text)
523
-
523
+
524
524
  return [TextContent(type="text", text="\n".join(tree_lines))]
525
-
525
+
526
+ except TypeError as e:
527
+ if "can't compare offset-naive and offset-aware datetimes" in str(e):
528
+ logger.error(
529
+ f"DateTime comparison error occurred despite patch. "
530
+ f"This may indicate a new code path in the library. Error: {e}"
531
+ )
532
+ return [TextContent(
533
+ type="text",
534
+ text=f"Encountered a datetime comparison issue. "
535
+ f"A workaround patch is applied, but this specific code path may need attention.\n"
536
+ f"Alternative: Use List_SharePoint_Folders for folder navigation."
537
+ )]
538
+ raise
526
539
  except Exception as e:
527
540
  return [TextContent(type="text", text=f"Error getting tree: {str(e)}")]
528
541
 
@@ -8,12 +8,46 @@ import time
8
8
  import random
9
9
  from typing import Optional
10
10
  from urllib.parse import urlparse
11
+ from datetime import datetime, timezone
11
12
  from office365.sharepoint.client_context import ClientContext
12
13
  from office365.runtime.auth.client_credential import ClientCredential
14
+ from office365.runtime.auth.token_response import TokenResponse
13
15
  import msal
14
16
 
15
17
  logger = logging.getLogger(__name__)
16
18
 
19
+ # Workaround for office365 library datetime comparison bug
20
+ # This will be fixed in the next library release
21
+ def _patch_datetime_bug():
22
+ """
23
+ Patches the office365 library's datetime comparison issue.
24
+ The library compares timezone-aware datetime.now(timezone.utc) with
25
+ timezone-naive datetime.max, causing a TypeError.
26
+ """
27
+ try:
28
+ from office365.runtime.auth import authentication_context
29
+
30
+ # Store the original __init__
31
+ original_init = authentication_context.AuthenticationContext.__init__
32
+
33
+ def patched_init(self, url):
34
+ original_init(self, url)
35
+ # Make token_expires timezone-aware to prevent comparison errors
36
+ if hasattr(self, '_token_expires') and self._token_expires is not None:
37
+ if self._token_expires.tzinfo is None:
38
+ # If it's datetime.max (naive), make it timezone-aware
39
+ if self._token_expires == datetime.max:
40
+ self._token_expires = datetime.max.replace(tzinfo=timezone.utc)
41
+
42
+ authentication_context.AuthenticationContext.__init__ = patched_init
43
+ logger.info("Applied datetime comparison patch for office365 library")
44
+
45
+ except Exception as e:
46
+ logger.warning(f"Could not apply datetime patch (may not be needed): {e}")
47
+
48
+ # Apply the patch when module is imported
49
+ _patch_datetime_bug()
50
+
17
51
 
18
52
  class SharePointAuthenticator:
19
53
  """
@@ -102,14 +136,18 @@ class SharePointAuthenticator:
102
136
 
103
137
  logger.info(f"Using SharePoint root scope: {sharepoint_root}/.default")
104
138
 
105
- def acquire_token() -> str:
139
+ def acquire_token():
106
140
  """
107
141
  Token callback used by office365 ClientContext.
108
142
  Retries transient network errors like ConnectionResetError(104).
143
+ Returns a TokenResponse object with tokenType and accessToken attributes.
109
144
  """
110
145
  now = int(time.time())
111
146
  if self._access_token and now < (self._access_token_exp - 60):
112
- return self._access_token
147
+ return TokenResponse(
148
+ access_token=self._access_token,
149
+ token_type="Bearer"
150
+ )
113
151
 
114
152
  last_err = None
115
153
  for attempt in range(1, 6): # 5 attempts
@@ -133,7 +171,8 @@ class SharePointAuthenticator:
133
171
  self._access_token_exp = int(time.time()) + expires_in
134
172
 
135
173
  logger.info(f"Successfully acquired token for {self.site_url}")
136
- return token
174
+ # Use from_json to automatically convert MSAL's snake_case to camelCase
175
+ return TokenResponse.from_json(result)
137
176
 
138
177
  except Exception as e:
139
178
  last_err = e
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-sharepoint-us
3
- Version: 2.0.7
3
+ Version: 2.0.10
4
4
  Summary: SharePoint MCP Server with Modern Azure AD Authentication
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/mdev26/mcp-sharepoint-us