feat(mcp): add legacy workstream alias deprecation warnings (STATE-WP-0069 T03)
Legacy MCP tools and the workstreams resource now return _deprecation payloads pointing to workplan-named replacements. get_domain_summary uses workplan-first prose and exposes a workplans key alongside the legacy workstreams field.
This commit is contained in:
parent
137cc92d89
commit
d431e69c04
4 changed files with 215 additions and 30 deletions
58
tests/test_mcp_legacy_deprecation.py
Normal file
58
tests/test_mcp_legacy_deprecation.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
import mcp_server.server as server
|
||||
|
||||
|
||||
def test_legacy_mcp_deprecation_payload_names_replacement() -> None:
|
||||
payload = server._legacy_mcp_deprecation(tool="create_workstream")
|
||||
assert payload["replacement"] == "create_workplan"
|
||||
assert payload["deprecated"] == "true"
|
||||
|
||||
|
||||
def test_attach_legacy_deprecation_preserves_success_payload() -> None:
|
||||
raw = server._attach_legacy_deprecation(
|
||||
"update_workstream_status",
|
||||
json.dumps({"id": "wp-1", "status": "active"}),
|
||||
)
|
||||
body = json.loads(raw)
|
||||
assert body["id"] == "wp-1"
|
||||
assert body["_deprecation"]["tool"] == "update_workstream_status"
|
||||
|
||||
|
||||
def _fake_get(path: str, params: dict | None = None):
|
||||
if path == "/topics":
|
||||
return [{"id": "topic-1", "domain_slug": "infotech", "title": "Infotech"}]
|
||||
if path == "/state/summary":
|
||||
return {
|
||||
"open_workstreams": [
|
||||
{
|
||||
"id": "wp-1",
|
||||
"topic_id": "topic-1",
|
||||
"title": "Goalless",
|
||||
"repo_id": "repo-1",
|
||||
}
|
||||
]
|
||||
}
|
||||
if path == "/decisions":
|
||||
return []
|
||||
if path == "/progress":
|
||||
return []
|
||||
if path == "/repos":
|
||||
return [{"id": "repo-1", "slug": "demo-repo", "domain_slug": "infotech"}]
|
||||
if path == "/repo-goals":
|
||||
return [{"id": "goal-1", "title": "Ship it", "description": "d", "priority": "high"}]
|
||||
if path == "/capability-catalog/":
|
||||
return []
|
||||
return []
|
||||
|
||||
|
||||
def test_get_domain_summary_goal_guidance_is_workplan_first(monkeypatch) -> None:
|
||||
monkeypatch.setattr(server, "_get", lambda path, params=None: _fake_get(path, params))
|
||||
payload = json.loads(server.get_domain_summary("infotech"))
|
||||
assert "workplans" in payload
|
||||
assert payload["workstreams"] == payload["workplans"]
|
||||
action = payload["goal_guidance"]["needs_workplan"][0]["action"]
|
||||
assert "workplan" in action.lower()
|
||||
assert "workstream is linked" not in action.lower()
|
||||
|
|
@ -75,8 +75,24 @@ class TestMCPWriteTools:
|
|||
)
|
||||
|
||||
assert body["id"] == "wp-1"
|
||||
assert body["_deprecation"]["replacement"] == "create_workplan"
|
||||
assert [path for path, _ in calls] == ["/workplans", "/progress"]
|
||||
|
||||
async def test_list_workstreams_legacy_alias_wraps_deprecation(self, monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
server,
|
||||
"_get",
|
||||
lambda path, params=None: [{"id": "wp-1", "title": "Example"}]
|
||||
if path == "/workplans"
|
||||
else [],
|
||||
)
|
||||
|
||||
body = await _call_tool("list_workstreams", {})
|
||||
|
||||
assert body["_deprecation"]["replacement"] == "list_workplans"
|
||||
assert body["workplans"] == [{"id": "wp-1", "title": "Example"}]
|
||||
assert body["workstreams"] == body["workplans"]
|
||||
|
||||
async def test_create_task_returns_rest_shape_and_emits_progress(self, monkeypatch):
|
||||
calls: list[tuple[str, dict[str, Any]]] = []
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue