mcp-sharepoint-us 2.0.9__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.
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/PKG-INFO +1 -1
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/pyproject.toml +1 -1
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint/__init__.py +19 -6
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint/auth.py +42 -10
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint_us.egg-info/PKG-INFO +1 -1
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/LICENSE +0 -0
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/README.md +0 -0
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/setup.cfg +0 -0
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint/__main__.py +0 -0
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint_us.egg-info/SOURCES.txt +0 -0
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint_us.egg-info/dependency_links.txt +0 -0
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint_us.egg-info/entry_points.txt +0 -0
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint_us.egg-info/requires.txt +0 -0
- {mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint_us.egg-info/top_level.txt +0 -0
|
@@ -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,18 +136,18 @@ class SharePointAuthenticator:
|
|
|
102
136
|
|
|
103
137
|
logger.info(f"Using SharePoint root scope: {sharepoint_root}/.default")
|
|
104
138
|
|
|
105
|
-
def acquire_token()
|
|
139
|
+
def acquire_token():
|
|
106
140
|
"""
|
|
107
141
|
Token callback used by office365 ClientContext.
|
|
108
142
|
Retries transient network errors like ConnectionResetError(104).
|
|
109
|
-
Returns a
|
|
143
|
+
Returns a TokenResponse object with tokenType and accessToken attributes.
|
|
110
144
|
"""
|
|
111
145
|
now = int(time.time())
|
|
112
146
|
if self._access_token and now < (self._access_token_exp - 60):
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
"
|
|
116
|
-
|
|
147
|
+
return TokenResponse(
|
|
148
|
+
access_token=self._access_token,
|
|
149
|
+
token_type="Bearer"
|
|
150
|
+
)
|
|
117
151
|
|
|
118
152
|
last_err = None
|
|
119
153
|
for attempt in range(1, 6): # 5 attempts
|
|
@@ -137,10 +171,8 @@ class SharePointAuthenticator:
|
|
|
137
171
|
self._access_token_exp = int(time.time()) + expires_in
|
|
138
172
|
|
|
139
173
|
logger.info(f"Successfully acquired token for {self.site_url}")
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
"accessToken": token
|
|
143
|
-
}
|
|
174
|
+
# Use from_json to automatically convert MSAL's snake_case to camelCase
|
|
175
|
+
return TokenResponse.from_json(result)
|
|
144
176
|
|
|
145
177
|
except Exception as e:
|
|
146
178
|
last_err = e
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint_us.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint_us.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint_us.egg-info/requires.txt
RENAMED
|
File without changes
|
{mcp_sharepoint_us-2.0.9 → mcp_sharepoint_us-2.0.10}/src/mcp_sharepoint_us.egg-info/top_level.txt
RENAMED
|
File without changes
|