diff --git a/everyrow-mcp/manifest.json b/everyrow-mcp/manifest.json index 2949ddfd..938b2072 100644 --- a/everyrow-mcp/manifest.json +++ b/everyrow-mcp/manifest.json @@ -73,6 +73,10 @@ "name": "everyrow_list_sessions", "description": "List everyrow sessions owned by the authenticated user (paginated)." }, + { + "name": "everyrow_list_session_tasks", + "description": "List all tasks in a session with their IDs, statuses, and types." + }, { "name": "everyrow_cancel", "description": "Cancel a running everyrow task. Use when the user wants to stop a task that is currently processing." diff --git a/everyrow-mcp/src/everyrow_mcp/models.py b/everyrow-mcp/src/everyrow_mcp/models.py index 2a5ebc98..323fe856 100644 --- a/everyrow-mcp/src/everyrow_mcp/models.py +++ b/everyrow-mcp/src/everyrow_mcp/models.py @@ -741,3 +741,11 @@ class ListSessionsInput(BaseModel): limit: int = Field( 25, ge=1, le=1000, description="Max sessions per page (default 25, max 1000)" ) + + +class ListSessionTasksInput(BaseModel): + """Input for listing tasks in a session.""" + + model_config = ConfigDict(extra="forbid") + + session_id: str = Field(description="The session ID to list tasks for") diff --git a/everyrow-mcp/src/everyrow_mcp/tools.py b/everyrow-mcp/src/everyrow_mcp/tools.py index 09889b60..92ef4e48 100644 --- a/everyrow-mcp/src/everyrow_mcp/tools.py +++ b/everyrow-mcp/src/everyrow_mcp/tools.py @@ -44,6 +44,7 @@ ForecastInput, HttpResultsInput, ListSessionsInput, + ListSessionTasksInput, MergeInput, ProgressInput, RankInput, @@ -1273,6 +1274,58 @@ async def everyrow_balance(ctx: EveryRowContext) -> list[TextContent]: ] +@mcp.tool( + name="everyrow_list_session_tasks", + structured_output=False, + annotations=ToolAnnotations( + title="List Tasks in a Session", + readOnlyHint=True, + destructiveHint=False, + idempotentHint=True, + openWorldHint=False, + ), +) +async def everyrow_list_session_tasks( + params: ListSessionTasksInput, ctx: EveryRowContext +) -> list[TextContent]: + """List all tasks in a session with their IDs, statuses, and types. + + Use this to find task IDs for a session so you can display previous results + with mcp__display__show_task(task_id, label). + """ + client = _get_client(ctx) + + try: + response = await client.get_async_httpx_client().request( + method="get", + url=f"/sessions/{params.session_id}/tasks", + ) + response.raise_for_status() + data = response.json() + except Exception as e: + return [TextContent(type="text", text=f"Error listing session tasks: {e!r}")] + + tasks = data.get("tasks", []) + if not tasks: + return [ + TextContent( + type="text", text=f"No tasks found in session {params.session_id}." + ) + ] + + lines = [f"Found {len(tasks)} task(s) in session {params.session_id}:\n"] + for t in tasks: + artifact = ( + f" | output_artifact: {t['artifact_id']}" if t.get("artifact_id") else "" + ) + lines.append( + f"- **{t['task_type']}** (task_id: {t['task_id']})\n" + f" Status: {t['status']} | Created: {t['created_at']}{artifact}" + ) + + return [TextContent(type="text", text="\n".join(lines))] + + @mcp.tool( name="everyrow_cancel", structured_output=False, diff --git a/everyrow-mcp/tests/test_mcp_e2e.py b/everyrow-mcp/tests/test_mcp_e2e.py index 660ee564..bace0b76 100644 --- a/everyrow-mcp/tests/test_mcp_e2e.py +++ b/everyrow-mcp/tests/test_mcp_e2e.py @@ -179,6 +179,7 @@ async def test_list_tools(self, _http_state): "everyrow_classify", "everyrow_dedupe", "everyrow_forecast", + "everyrow_list_session_tasks", "everyrow_list_sessions", "everyrow_merge", "everyrow_progress",