From 6b05d9ea18b41ae74a9c79e330223a4300458550 Mon Sep 17 00:00:00 2001 From: Max Isbey <224885523+maxisbey@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:02:41 +0000 Subject: [PATCH] fix: allow Any type for logging message parameter Change the type annotation of the message parameter in Context.log(), Context.debug(), Context.info(), Context.warning(), and Context.error() from str to Any. The MCP spec defines the log data field as: data: unknown - "Any JSON serializable type is allowed here" This allows MCP servers to send rich structured notifications: ctx.info({"event": "progress", "percent": 50}) The parameter name is kept as message for backward compatibility. Fixes #397 --- .github/workflows/claude-code-review.yml | 33 ------------------------ src/mcp/server/mcpserver/context.py | 12 ++++----- 2 files changed, 6 insertions(+), 39 deletions(-) delete mode 100644 .github/workflows/claude-code-review.yml diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml deleted file mode 100644 index 514f979d7..000000000 --- a/.github/workflows/claude-code-review.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Source: https://github.com/anthropics/claude-code-action/blob/main/docs/code-review.md -name: Claude Code Review - -on: - pull_request: - types: [opened, synchronize, ready_for_review, reopened] - -jobs: - claude-review: - # Fork PRs don't have access to secrets or OIDC tokens, so the action - # cannot authenticate. See https://github.com/anthropics/claude-code-action/issues/339 - if: github.event.pull_request.head.repo.fork == false && github.actor != 'dependabot[bot]' - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - issues: read - id-token: write - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - fetch-depth: 1 - - - name: Run Claude Code Review - id: claude-review - uses: anthropics/claude-code-action@2f8ba26a219c06cfb0f468eef8d97055fa814f97 # v1.0.53 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - plugin_marketplaces: "https://github.com/anthropics/claude-code.git" - plugins: "code-review@claude-code-plugins" - prompt: "/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}" diff --git a/src/mcp/server/mcpserver/context.py b/src/mcp/server/mcpserver/context.py index 1538adc7c..9a54f9910 100644 --- a/src/mcp/server/mcpserver/context.py +++ b/src/mcp/server/mcpserver/context.py @@ -187,7 +187,7 @@ async def elicit_url( async def log( self, level: Literal["debug", "info", "warning", "error"], - message: str, + message: Any, *, logger_name: str | None = None, extra: dict[str, Any] | None = None, @@ -196,7 +196,7 @@ async def log( Args: level: Log level (debug, info, warning, error) - message: Log message + message: The data to log. Any JSON-serializable type (string, dict, list, etc.) logger_name: Optional logger name extra: Optional dictionary with additional structured data to include """ @@ -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, message: 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) - async def info(self, message: str, *, logger_name: str | None = None, extra: dict[str, Any] | None = None) -> None: + async def info(self, message: 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) async def warning( - self, message: str, *, logger_name: str | None = None, extra: dict[str, Any] | None = None + self, message: 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) - async def error(self, message: str, *, logger_name: str | None = None, extra: dict[str, Any] | None = None) -> None: + async def error(self, message: 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)