Skip to content
Open
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: 5 additions & 2 deletions examples/mcpserver/logging_and_progress.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
async def echo(text: str, ctx: Context) -> str:
"""Echo the input text sending log messages and progress updates during processing."""
await ctx.report_progress(progress=0, total=100)
await ctx.info("Starting to process echo for input: " + text)

# Test logging with objects (not just strings) - now valid per MCP spec
await ctx.info({"status": "starting", "input_length": len(text), "text": text})

await asyncio.sleep(2)

Expand All @@ -21,7 +23,8 @@ async def echo(text: str, ctx: Context) -> str:

await asyncio.sleep(2)

await ctx.info("Finished processing echo for input: " + text)
# Test logging with a list
await ctx.info(["processing", "complete", "returning"])
await ctx.report_progress(progress=100, total=100)

# Progress notifications are process asynchronously by the client.
Expand Down
24 changes: 12 additions & 12 deletions src/mcp/server/mcpserver/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ async def elicit_url(
async def log(
self,
level: Literal["debug", "info", "warning", "error"],
message: str,
data: Any,
*,
logger_name: str | None = None,
extra: dict[str, Any] | None = None,
Expand All @@ -196,15 +196,15 @@ async def log(

Args:
level: Log level (debug, info, warning, error)
message: Log message
data: The data to be logged, such as a string message or an object. Any JSON serializable type is allowed.
logger_name: Optional logger name
extra: Optional dictionary with additional structured data to include
"""

if extra:
log_data = {"message": message, **extra}
log_data = {"message": data, **extra}
else:
log_data = message
log_data = data

await self.request_context.session.send_log_message(
level=level,
Expand Down Expand Up @@ -261,20 +261,20 @@ async def close_standalone_sse_stream(self) -> None:
await self._request_context.close_standalone_sse_stream()

# Convenience methods for common log levels
async def debug(self, message: str, *, logger_name: str | None = None, extra: dict[str, Any] | None = None) -> None:
async def debug(self, data: Any, *, logger_name: str | None = None, extra: dict[str, Any] | None = None) -> None:
"""Send a debug log message."""
await self.log("debug", message, logger_name=logger_name, extra=extra)
await self.log("debug", data, logger_name=logger_name, extra=extra)

async def info(self, message: str, *, logger_name: str | None = None, extra: dict[str, Any] | None = None) -> None:
async def info(self, data: Any, *, logger_name: str | None = None, extra: dict[str, Any] | None = None) -> None:
"""Send an info log message."""
await self.log("info", message, logger_name=logger_name, extra=extra)
await self.log("info", data, logger_name=logger_name, extra=extra)

async def warning(
self, message: str, *, logger_name: str | None = None, extra: dict[str, Any] | None = None
self, data: Any, *, logger_name: str | None = None, extra: dict[str, Any] | None = None
) -> None:
"""Send a warning log message."""
await self.log("warning", message, logger_name=logger_name, extra=extra)
await self.log("warning", data, logger_name=logger_name, extra=extra)

async def error(self, message: str, *, logger_name: str | None = None, extra: dict[str, Any] | None = None) -> None:
async def error(self, data: Any, *, logger_name: str | None = None, extra: dict[str, Any] | None = None) -> None:
"""Send an error log message."""
await self.log("error", message, logger_name=logger_name, extra=extra)
await self.log("error", data, logger_name=logger_name, extra=extra)
Loading