fix(mcp): list tools return rows that say what a record is, not what it says (#4061)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 49s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Successful in 1m31s
CI & Build / Build & push image (push) Successful in 22s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 49s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Successful in 1m31s
CI & Build / Build & push image (push) Successful in 22s
list_tasks returned every row's to_dict(), body included: a project's todo list came to 93-165k characters, past what an MCP client accepts inline, so the list arrived as a file to page through (the #4045 failure, one call over). - notes.brief_row: id, title, type, project, tags, updated_at; for tasks, status, kind, priority, milestone id and title; description, parent and due date only when set. - milestones.titles_for: one query for the milestone titles a page of rows names. - Brief rows on list_tasks, list_notes, get_milestone's steps, get_system and list_system_records. get_task / get_note / get_snippet read a record in full, and each docstring says so. - tests/test_list_rows_brief.py pins the ceiling: 100 rows of ~5k-character step plans stay under 40k characters. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
This commit is contained in:
@@ -6,7 +6,7 @@ import pytest
|
||||
from scribe.mcp.tools.milestones import (
|
||||
list_milestones, get_milestone, create_milestone, update_milestone,
|
||||
)
|
||||
from tests.helpers import fake_milestone
|
||||
from tests.helpers import fake_milestone, fake_task
|
||||
|
||||
|
||||
pytestmark = pytest.mark.usefixtures("_bind_user")
|
||||
@@ -111,8 +111,7 @@ async def test_update_milestone_sends_body():
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_milestone_returns_body_steps_and_rules():
|
||||
m = fake_milestone(id=5, project_id=3, body="## Goal")
|
||||
step = MagicMock()
|
||||
step.to_dict.return_value = {"id": 9, "title": "step 1", "status": "todo"}
|
||||
step = fake_task(id=9, title="step 1", milestone_id=5, body="a long step body")
|
||||
applicable = {"rules": [{"id": 1, "title": "r"}], "truncated": False,
|
||||
"project_rules": [{"id": 3, "title": "own"}]}
|
||||
with patch("scribe.mcp.tools.milestones.milestones_svc.get_milestone",
|
||||
@@ -126,7 +125,10 @@ async def test_get_milestone_returns_body_steps_and_rules():
|
||||
out = await get_milestone(milestone_id=5)
|
||||
assert out["milestone"]["body"] == "## Goal"
|
||||
assert out["milestone"]["total"] == 1
|
||||
assert out["steps"] == [{"id": 9, "title": "step 1", "status": "todo"}]
|
||||
assert [(s["id"], s["title"], s["status"]) for s in out["steps"]] == [(9, "step 1", "todo")]
|
||||
# A step's body is get_task's job (#4061); its placement is not.
|
||||
assert "body" not in out["steps"][0]
|
||||
assert out["steps"][0]["milestone_title"] == m.title
|
||||
assert out["applicable_rules"] == [{"id": 1, "title": "r"}]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user