Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions temporal_mcp/handlers/workflow_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,16 @@ async def get_workflow_history(client: Client, args: dict) -> list[TextContent]:

Args:
client: Connected Temporal client
args: Arguments containing workflow_id and optional limit
args: Arguments containing workflow_id and optional limit, run_id

Returns:
Workflow history events
"""
workflow_id = args["workflow_id"]
limit = args.get("limit", 1000)
run_id = args.get("run_id")

handle = client.get_workflow_handle(workflow_id)
handle = client.get_workflow_handle(workflow_id, run_id=run_id)

events = []
scheduled_activities: dict[int, dict[str, Any]] = {}
Expand All @@ -249,7 +250,7 @@ async def get_workflow_history(client: Client, args: dict) -> list[TextContent]:
if count >= limit:
break

return [TextContent(type="text", text=json.dumps({"workflow_id": workflow_id, "events": events, "count": len(events)}, indent=2))]
return [TextContent(type="text", text=json.dumps({"workflow_id": workflow_id, "run_id": run_id, "events": events, "count": len(events)}, indent=2))]


def _workflow_history_event_to_dict(event: Any, scheduled_activities: dict[int, dict[str, Any]], initiated_child_workflows: dict[int, dict[str, Any]]) -> dict[str, Any]:
Expand Down
1 change: 1 addition & 0 deletions temporal_mcp/tools/tool_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def get_all_tools() -> list[Tool]:
"type": "object",
"properties": {
"workflow_id": {"type": "string", "description": "The workflow execution ID"},
"run_id": {"type": "string", "description": "Optional run ID for the workflow execution; omit to target the latest run"},
"limit": {"type": "number", "description": "Maximum number of history events to return (default: 1000)"},
},
"required": ["workflow_id"],
Expand Down
38 changes: 38 additions & 0 deletions tests/test_workflow_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,44 @@ async def mock_fetch_history_events():
assert "__raw__" not in failed_attrs
assert "result" not in failed_attrs

@pytest.mark.asyncio
async def test_get_workflow_history_passes_run_id_when_provided(self, mock_client):
async def mock_fetch_history_events():
if False:
yield None

mock_handle = AsyncMock()
mock_handle.fetch_history_events = mock_fetch_history_events
mock_client.get_workflow_handle = MagicMock(return_value=mock_handle)

result = await workflow_handlers.get_workflow_history(mock_client, {"workflow_id": "test-workflow-123", "run_id": "run-xyz"})

response = json.loads(result[0].text)
assert response["workflow_id"] == "test-workflow-123"
assert response["run_id"] == "run-xyz"
assert response["events"] == []
assert response["count"] == 0
mock_client.get_workflow_handle.assert_called_once_with("test-workflow-123", run_id="run-xyz")

@pytest.mark.asyncio
async def test_get_workflow_history_defaults_run_id_to_none(self, mock_client):
async def mock_fetch_history_events():
if False:
yield None

mock_handle = AsyncMock()
mock_handle.fetch_history_events = mock_fetch_history_events
mock_client.get_workflow_handle = MagicMock(return_value=mock_handle)

result = await workflow_handlers.get_workflow_history(mock_client, {"workflow_id": "test-workflow-123"})

response = json.loads(result[0].text)
assert response["workflow_id"] == "test-workflow-123"
assert response["run_id"] is None
assert response["events"] == []
assert response["count"] == 0
mock_client.get_workflow_handle.assert_called_once_with("test-workflow-123", run_id=None)


class TestGetWorkflowEvent:
@pytest.mark.asyncio
Expand Down
Loading