Skip to main content
notifications/message is a server → client notification. The server uses it to send structured log messages to the client (warnings, debug traces, audit lines) — typically rendered in a side panel in clients like Claude Desktop and Cursor. GetMCP exposes a callable emitter API. The level filter the client requested via logging/setLevel is honoured before queuing.

Wire-level Shape

{
  "jsonrpc": "2.0",
  "method":  "notifications/message",
  "params": {
    "level":  "warning",
    "logger": "getmcp.tool.create_invoice",
    "data": {
      "message":   "Stripe rate limit at 80% of cap",
      "remaining": 12,
      "limit":     60
    }
  }
}
params.level
string
required
One of debug, info, notice, warning, error, critical, alert, emergency (RFC 5424 syslog levels).
params.logger
string
Optional logger name — useful for routing in the client. Convention: dot-notation per subsystem (getmcp.tool.<name>, getmcp.auth, etc.).
params.data
object | string
required
The log payload. Most clients render data.message as the headline and the rest of the object as structured detail.

Emitting From PHP

use GetMCP\Protocol\MessageEmitter;

MessageEmitter::emit(
    $session_id,
    'warning',                            // level
    'getmcp.tool.create_invoice',         // logger
    array(
        'message'   => 'Stripe rate limit at 80% of cap',
        'remaining' => 12,
        'limit'     => 60,
    )
);
The emitter checks the session’s current log level (set by the client via logging/setLevel) and drops the message if it’s below the threshold. If no level was set, the default is infodebug messages are suppressed.

Delivery Model

Like other server-initiated traffic on Streamable HTTP, log messages are queued in the per-session outbound queue and delivered as part of the next JSON-RPC response batch. Clients that already handle batched responses (the official SDKs do) will surface them in real time as they arrive.

When to Emit

Good fits:
  • Auditable side effects — “Created Stripe invoice inv_abc123
  • Soft warnings the user should see — “Upstream API returned a 429; retried after 1.2s”
  • Debug traces gated behind log level — keep them at debug so production clients don’t see them
Bad fits:
  • Tool errors — return them as isError: true in the tools/call response so the model knows it failed
  • Per-request telemetry — write to your own log destination; notifications/message is for the user, not for ops dashboards

Log notifications are advisory and lossy — clients may render them, drop them, or rate-limit them. Don’t rely on them for state that has to reach the user; surface that as part of the tool response instead.