Skip to content
Merged
7 changes: 6 additions & 1 deletion src/mcp/client/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,11 @@ async def send_ping(self) -> types.EmptyResult:
)

async def send_progress_notification(
self, progress_token: str | int, progress: float, total: float | None = None
self,
progress_token: str | int,
progress: float,
total: float | None = None,
message: str | None = None,
) -> None:
"""Send a progress notification."""
await self.send_notification(
Expand All @@ -179,6 +183,7 @@ async def send_progress_notification(
progressToken=progress_token,
progress=progress,
total=total,
message=message,
),
),
)
Expand Down
8 changes: 6 additions & 2 deletions src/mcp/server/fastmcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,13 +952,14 @@ def request_context(self) -> RequestContext[ServerSessionT, LifespanContextT]:
return self._request_context

async def report_progress(
self, progress: float, total: float | None = None
self, progress: float, total: float | None = None, message: str | None = None
) -> None:
"""Report progress for the current operation.

Args:
progress: Current progress value e.g. 24
total: Optional total value e.g. 100
message: Optional message e.g. Starting render...
"""

progress_token = (
Expand All @@ -971,7 +972,10 @@ async def report_progress(
return

await self.request_context.session.send_progress_notification(
progress_token=progress_token, progress=progress, total=total
progress_token=progress_token,
progress=progress,
total=total,
message=message,
)

async def read_resource(self, uri: str | AnyUrl) -> Iterable[ReadResourceContents]:
Expand Down
12 changes: 9 additions & 3 deletions src/mcp/server/lowlevel/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ async def handle_list_resource_templates() -> list[types.ResourceTemplate]:
3. Define notification handlers if needed:
@server.progress_notification()
async def handle_progress(
progress_token: str | int, progress: float, total: float | None
progress_token: str | int, progress: float, total: float | None,
message: str | None
) -> None:
# Implementation

Expand Down Expand Up @@ -427,13 +428,18 @@ async def handler(req: types.CallToolRequest):

def progress_notification(self):
def decorator(
func: Callable[[str | int, float, float | None], Awaitable[None]],
func: Callable[
[str | int, float, float | None, str | None], Awaitable[None]
],
):
logger.debug("Registering handler for ProgressNotification")

async def handler(req: types.ProgressNotification):
await func(
req.params.progressToken, req.params.progress, req.params.total
req.params.progressToken,
req.params.progress,
req.params.total,
req.params.message,
)

self.notification_handlers[types.ProgressNotification] = handler
Expand Down
2 changes: 2 additions & 0 deletions src/mcp/server/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ async def send_progress_notification(
progress_token: str | int,
progress: float,
total: float | None = None,
message: str | None = None,
related_request_id: str | None = None,
) -> None:
"""Send a progress notification."""
Expand All @@ -293,6 +294,7 @@ async def send_progress_notification(
progressToken=progress_token,
progress=progress,
total=total,
message=message,
),
)
),
Expand Down
4 changes: 2 additions & 2 deletions src/mcp/shared/progress.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ class ProgressContext(
total: float | None
current: float = field(default=0.0, init=False)

async def progress(self, amount: float) -> None:
async def progress(self, amount: float, message: str | None = None) -> None:
self.current += amount

await self.session.send_progress_notification(
self.progress_token, self.current, total=self.total
self.progress_token, self.current, total=self.total, message=message
)


Expand Down
6 changes: 5 additions & 1 deletion src/mcp/shared/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,11 @@ async def _received_notification(self, notification: ReceiveNotificationT) -> No
"""

async def send_progress_notification(
self, progress_token: str | int, progress: float, total: float | None = None
self,
progress_token: str | int,
progress: float,
total: float | None = None,
message: str | None = None,
) -> None:
"""
Sends a progress notification for a request that is currently being
Expand Down
5 changes: 5 additions & 0 deletions src/mcp/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,11 @@ class ProgressNotificationParams(NotificationParams):
total is unknown.
"""
total: float | None = None
"""
Message related to progress. This should provide relevant human readable
progress information.
"""
message: str | None = None
"""Total number of items to process (or total progress required), if known."""
model_config = ConfigDict(extra="allow")

Expand Down
6 changes: 3 additions & 3 deletions tests/issues/test_176_progress_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ async def test_progress_token_zero_first_call():
mock_session.send_progress_notification.call_count == 3
), "All progress notifications should be sent"
mock_session.send_progress_notification.assert_any_call(
progress_token=0, progress=0.0, total=10.0
progress_token=0, progress=0.0, total=10.0, message=None
)
mock_session.send_progress_notification.assert_any_call(
progress_token=0, progress=5.0, total=10.0
progress_token=0, progress=5.0, total=10.0, message=None
)
mock_session.send_progress_notification.assert_any_call(
progress_token=0, progress=10.0, total=10.0
progress_token=0, progress=10.0, total=10.0, message=None
)
Loading
Loading