m365-roadmap-mcp 0.3.0__py3-none-any.whl → 0.3.1__py3-none-any.whl
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.
- m365_roadmap_mcp/server.py +4 -2
- m365_roadmap_mcp/tools/search.py +78 -5
- {m365_roadmap_mcp-0.3.0.dist-info → m365_roadmap_mcp-0.3.1.dist-info}/METADATA +6 -1
- {m365_roadmap_mcp-0.3.0.dist-info → m365_roadmap_mcp-0.3.1.dist-info}/RECORD +7 -7
- {m365_roadmap_mcp-0.3.0.dist-info → m365_roadmap_mcp-0.3.1.dist-info}/WHEEL +0 -0
- {m365_roadmap_mcp-0.3.0.dist-info → m365_roadmap_mcp-0.3.1.dist-info}/entry_points.txt +0 -0
- {m365_roadmap_mcp-0.3.0.dist-info → m365_roadmap_mcp-0.3.1.dist-info}/licenses/LICENSE +0 -0
m365_roadmap_mcp/server.py
CHANGED
|
@@ -27,7 +27,8 @@ mcp = FastMCP(
|
|
|
27
27
|
"- platform: filter by platform ('Web', 'Desktop', 'iOS', 'Android', 'Mac')\n"
|
|
28
28
|
"- rollout_date: filter by rollout start date (e.g. 'December 2026')\n"
|
|
29
29
|
"- preview_date: filter by preview availability date (e.g. 'July 2026')\n"
|
|
30
|
-
"- modified_within_days: show only features modified within N days\n
|
|
30
|
+
"- modified_within_days: show only features modified within N days\n"
|
|
31
|
+
"- include_facets: include taxonomy facets with counts (default: False)\n\n"
|
|
31
32
|
"Tips:\n"
|
|
32
33
|
"- To get feature details, use feature_id with the roadmap ID.\n"
|
|
33
34
|
"- To check cloud availability, use cloud_instance with a feature_id or "
|
|
@@ -35,7 +36,8 @@ mcp = FastMCP(
|
|
|
35
36
|
"supported instances.\n"
|
|
36
37
|
"- To list recent additions, use added_within_days (e.g. 30 for last month).\n"
|
|
37
38
|
"- To filter by release phase or platform, use release_phase or platform filters.\n"
|
|
38
|
-
"- To search by dates, use rollout_date or preview_date with partial date strings
|
|
39
|
+
"- To search by dates, use rollout_date or preview_date with partial date strings.\n"
|
|
40
|
+
"- To discover available filter values, use include_facets=True (optionally with limit=0)."
|
|
39
41
|
),
|
|
40
42
|
)
|
|
41
43
|
|
m365_roadmap_mcp/tools/search.py
CHANGED
|
@@ -1,8 +1,55 @@
|
|
|
1
1
|
"""Search tool for querying and filtering M365 Roadmap features."""
|
|
2
2
|
|
|
3
|
+
from collections import Counter
|
|
3
4
|
from datetime import datetime, timedelta, timezone
|
|
4
5
|
|
|
5
6
|
from ..feeds.m365_api import fetch_features
|
|
7
|
+
from ..models.feature import RoadmapFeature
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def compute_facets(features: list[RoadmapFeature]) -> dict:
|
|
11
|
+
"""Compute facet counts from a list of features.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
features: List of RoadmapFeature objects to analyze
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Dictionary with facet categories and counts
|
|
18
|
+
"""
|
|
19
|
+
products = Counter()
|
|
20
|
+
statuses = Counter()
|
|
21
|
+
release_phases = Counter()
|
|
22
|
+
platforms = Counter()
|
|
23
|
+
cloud_instances = Counter()
|
|
24
|
+
|
|
25
|
+
for feature in features:
|
|
26
|
+
# Products (from tags)
|
|
27
|
+
for tag in feature.tags:
|
|
28
|
+
products[tag] += 1
|
|
29
|
+
|
|
30
|
+
# Status
|
|
31
|
+
if feature.status:
|
|
32
|
+
statuses[feature.status] += 1
|
|
33
|
+
|
|
34
|
+
# Release phases
|
|
35
|
+
for rp in feature.release_phases:
|
|
36
|
+
release_phases[rp] += 1
|
|
37
|
+
|
|
38
|
+
# Platforms
|
|
39
|
+
for p in feature.platforms:
|
|
40
|
+
platforms[p] += 1
|
|
41
|
+
|
|
42
|
+
# Cloud instances
|
|
43
|
+
for ci in feature.cloud_instances:
|
|
44
|
+
cloud_instances[ci] += 1
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
"products": [{"name": k, "count": v} for k, v in products.most_common()],
|
|
48
|
+
"statuses": [{"name": k, "count": v} for k, v in statuses.most_common()],
|
|
49
|
+
"release_phases": [{"name": k, "count": v} for k, v in release_phases.most_common()],
|
|
50
|
+
"platforms": [{"name": k, "count": v} for k, v in platforms.most_common()],
|
|
51
|
+
"cloud_instances": [{"name": k, "count": v} for k, v in cloud_instances.most_common()],
|
|
52
|
+
}
|
|
6
53
|
|
|
7
54
|
|
|
8
55
|
async def search_roadmap(
|
|
@@ -17,6 +64,7 @@ async def search_roadmap(
|
|
|
17
64
|
rollout_date: str | None = None,
|
|
18
65
|
preview_date: str | None = None,
|
|
19
66
|
modified_within_days: int | None = None,
|
|
67
|
+
include_facets: bool = False,
|
|
20
68
|
limit: int = 10,
|
|
21
69
|
) -> dict:
|
|
22
70
|
"""Search the Microsoft 365 Roadmap for features matching keywords and filters.
|
|
@@ -61,6 +109,10 @@ async def search_roadmap(
|
|
|
61
109
|
against publicPreviewDate, e.g. "July 2026").
|
|
62
110
|
modified_within_days: Optional number of days to look back for recently modified
|
|
63
111
|
features (clamped to 1-365).
|
|
112
|
+
include_facets: When True, includes taxonomy facets (products, statuses,
|
|
113
|
+
release_phases, platforms, cloud_instances) with occurrence counts in
|
|
114
|
+
the response. Use with limit=0 to get only facets without features.
|
|
115
|
+
Facets are computed from matched results after filters are applied.
|
|
64
116
|
limit: Maximum number of results to return (default: 10, max: 100).
|
|
65
117
|
Ignored when feature_id is provided.
|
|
66
118
|
|
|
@@ -69,6 +121,7 @@ async def search_roadmap(
|
|
|
69
121
|
- total_found: Number of features matching the filters (before applying limit)
|
|
70
122
|
- features: List of matching feature objects (up to limit)
|
|
71
123
|
- filters_applied: Summary of which filters were used
|
|
124
|
+
- facets: (Optional) Dictionary with facet categories and counts when include_facets=True
|
|
72
125
|
"""
|
|
73
126
|
features = await fetch_features()
|
|
74
127
|
|
|
@@ -87,8 +140,9 @@ async def search_roadmap(
|
|
|
87
140
|
"filters_applied": {"feature_id": feature_id},
|
|
88
141
|
}
|
|
89
142
|
|
|
90
|
-
# Clamp limit to reasonable bounds
|
|
91
|
-
|
|
143
|
+
# Clamp limit to reasonable bounds (allow 0 when only requesting facets)
|
|
144
|
+
min_limit = 0 if include_facets else 1
|
|
145
|
+
limit = max(min_limit, min(limit, 100))
|
|
92
146
|
|
|
93
147
|
# Compute recency cutoff if requested
|
|
94
148
|
cutoff = None
|
|
@@ -141,13 +195,25 @@ async def search_roadmap(
|
|
|
141
195
|
continue
|
|
142
196
|
|
|
143
197
|
# Rollout date filter (partial match against publicDisclosureAvailabilityDate)
|
|
198
|
+
# API uses "CY" prefix (e.g., "December CY2026") but users typically omit it
|
|
144
199
|
if rollout_date_lower:
|
|
145
|
-
if not feature.public_disclosure_date
|
|
200
|
+
if not feature.public_disclosure_date:
|
|
201
|
+
continue
|
|
202
|
+
# Normalize by removing "cy" prefix for comparison
|
|
203
|
+
normalized_date = feature.public_disclosure_date.lower().replace(" cy", " ")
|
|
204
|
+
normalized_query = rollout_date_lower.replace(" cy", " ")
|
|
205
|
+
if normalized_query not in normalized_date:
|
|
146
206
|
continue
|
|
147
207
|
|
|
148
208
|
# Preview date filter (partial match against publicPreviewDate)
|
|
209
|
+
# API uses "CY" prefix (e.g., "July CY2026") but users typically omit it
|
|
149
210
|
if preview_date_lower:
|
|
150
|
-
if not feature.public_preview_date
|
|
211
|
+
if not feature.public_preview_date:
|
|
212
|
+
continue
|
|
213
|
+
# Normalize by removing "cy" prefix for comparison
|
|
214
|
+
normalized_date = feature.public_preview_date.lower().replace(" cy", " ")
|
|
215
|
+
normalized_query = preview_date_lower.replace(" cy", " ")
|
|
216
|
+
if normalized_query not in normalized_date:
|
|
151
217
|
continue
|
|
152
218
|
|
|
153
219
|
# Keyword search (title + description)
|
|
@@ -213,8 +279,15 @@ async def search_roadmap(
|
|
|
213
279
|
if not filters_applied:
|
|
214
280
|
filters_applied["note"] = "No filters applied, returning most recent features"
|
|
215
281
|
|
|
216
|
-
|
|
282
|
+
# Build response
|
|
283
|
+
result = {
|
|
217
284
|
"total_found": len(matched),
|
|
218
285
|
"features": [f.to_dict() for f in matched[:limit]],
|
|
219
286
|
"filters_applied": filters_applied,
|
|
220
287
|
}
|
|
288
|
+
|
|
289
|
+
# Add facets if requested (computed from matched results)
|
|
290
|
+
if include_facets:
|
|
291
|
+
result["facets"] = compute_facets(matched)
|
|
292
|
+
|
|
293
|
+
return result
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: m365-roadmap-mcp
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: MCP server for querying the Microsoft 365 Roadmap
|
|
5
5
|
Project-URL: Homepage, https://github.com/jonnybottles/M365-roadmap-mcp-server
|
|
6
6
|
Project-URL: Repository, https://github.com/jonnybottles/M365-roadmap-mcp-server
|
|
@@ -189,6 +189,11 @@ Provides a single **`search_roadmap`** tool that handles all M365 roadmap querie
|
|
|
189
189
|
- **Cloud instance filter** -- Filter by cloud instance (GCC, GCC High, DoD)
|
|
190
190
|
- **Feature lookup** -- Retrieve full metadata for a specific roadmap ID
|
|
191
191
|
- **Recent additions** -- List features added within the last N days
|
|
192
|
+
- **Release phase filter** -- Filter by release phase (General Availability, Preview, Targeted Release)
|
|
193
|
+
- **Platform filter** -- Filter by platform (Web, Desktop, iOS, Android, Mac)
|
|
194
|
+
- **Rollout date filter** -- Filter by rollout start date (e.g., "December 2026", "2026")
|
|
195
|
+
- **Preview date filter** -- Filter by preview availability date (e.g., "July 2026")
|
|
196
|
+
- **Recently modified** -- List features modified within the last N days
|
|
192
197
|
|
|
193
198
|
## Data Source
|
|
194
199
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
m365_roadmap_mcp/__init__.py,sha256=ydNG2ztexAZvnKchX4y1FnQ_atvfc1WGa4E8Y45lPjk,96
|
|
2
2
|
m365_roadmap_mcp/__main__.py,sha256=D9mYXV4TlB361LHfDDwvxsybz0_7EUsseJ3pZkS9AOo,84
|
|
3
|
-
m365_roadmap_mcp/server.py,sha256=
|
|
3
|
+
m365_roadmap_mcp/server.py,sha256=bRqk4b51sRdfrv1r5g-s4Qc-opVTurHryLLHKjn3RLI,2970
|
|
4
4
|
m365_roadmap_mcp/feeds/__init__.py,sha256=mVerRhM3n8iwoiupqp4rhqOGOpR2WbtA6MErj5pLG3g,38
|
|
5
5
|
m365_roadmap_mcp/feeds/m365_api.py,sha256=Elkx_4N42H8v-b93Y9jbt5y2zq6jB8gbWZAjQ3dwWVA,2594
|
|
6
6
|
m365_roadmap_mcp/models/__init__.py,sha256=Ml_sDvBRyK40Pq4Of0pDExGEBTjyh0QWB4VLu_zKkks,112
|
|
@@ -9,9 +9,9 @@ m365_roadmap_mcp/tools/__init__.py,sha256=nsNOC46HR1ElncjDck0CjOyeCkh1ZugH8YOiaC
|
|
|
9
9
|
m365_roadmap_mcp/tools/cloud.py,sha256=NuvztbKyMLc9pKZYD98kih23e09dAKnAeaEXZig2ky0,2562
|
|
10
10
|
m365_roadmap_mcp/tools/details.py,sha256=jgIpi1BhraHPuMT9tQi3d8ikvLF0EZR7p_D7spNlWL0,1067
|
|
11
11
|
m365_roadmap_mcp/tools/recent.py,sha256=Y9I5SS0I2MsV0i98QKtzXrL14AF5yfEyC3f6RiAxj-g,1709
|
|
12
|
-
m365_roadmap_mcp/tools/search.py,sha256=
|
|
13
|
-
m365_roadmap_mcp-0.3.
|
|
14
|
-
m365_roadmap_mcp-0.3.
|
|
15
|
-
m365_roadmap_mcp-0.3.
|
|
16
|
-
m365_roadmap_mcp-0.3.
|
|
17
|
-
m365_roadmap_mcp-0.3.
|
|
12
|
+
m365_roadmap_mcp/tools/search.py,sha256=IaRRHfWF3FixF709oiVgxxtYE4lXHuIWl0HMshFqnNA,12146
|
|
13
|
+
m365_roadmap_mcp-0.3.1.dist-info/METADATA,sha256=kh3J7VH6yEyt6tOFf39rW1mXFG0qH45pRZ9b7y0KU3A,7932
|
|
14
|
+
m365_roadmap_mcp-0.3.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
15
|
+
m365_roadmap_mcp-0.3.1.dist-info/entry_points.txt,sha256=GNzyIHa06s1_7BMZzkI4Dsury7aBgUmOYiSXFGNgE6M,66
|
|
16
|
+
m365_roadmap_mcp-0.3.1.dist-info/licenses/LICENSE,sha256=NNt5lEWzqGxqVCVmj-VEeWFxXhtbgCNwFhYcCUffWDI,1071
|
|
17
|
+
m365_roadmap_mcp-0.3.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|