Logging

logging/setLevel, legacy only.

Note

logging/setLevel and the Logging feature as a whole were deprecated in 2026-07-28. Modern clients set the level per request via _meta["io.modelcontextprotocol/logLevel"] — see request-scoped streaming.

Legacy clients set a server-wide log level once, and the server pushes notifications/message at or above that level over the SSE stream.

Important

Logging is opt-in on the server. logging/setLevel is only served by a server that declares the logging capability — set logging: true, or an onLogLevelSet callback, which implies it. Without either, the method answers -32601 Method not found, no level is ever in force, and ctx.log() emits nothing.

defineMcpHandler({
  name: "my-server",
  version: "1.0.0",
  onLogLevelSet(level, event) {
    console.log(`Client requested log level: ${level}`);
  },
  tools: [/* ... */],
});

The level is validated against the eight MCP levels before your callback runs:

debug · info · notice · warning · error · critical · alert · emergency

Declaring onLogLevelSet is one of the two things that advertise logging: {} in the initialize capabilities — and, therefore, one of the two things that make this method exist at all; see the note on logging: true below. The callback is a notification hook, not bookkeeping: h3-mcp already records the level per session, so nothing you write has to.

Important

Log messages are sent to the client. Treat them as output for a third party: no credentials, no tokens, no internal hostnames or stack traces. Everything that applies to error messages applies here.

To actually send a log message, use event.context.mcp.log() — the same call on both eras. It gates on the level in force (here, the one this session set), which only a server that declared the capability can ever have, so the note below is a prerequisite rather than an aside:

event.context.mcp?.log?.("warning", { retries: 3 }, "importer");

On legacy the message travels on the request's own SSE response, so the client must send Accept: text/event-stream with the call. Anything logged below the requested level, or by a request whose client asked for no logs at all, is dropped.

Read more in Request-scoped streaming.

Important

A server that sends notifications/message MUST declare the logging capability, so h3-mcp declares it and gates emission on the same switch. If a handler calls ctx.log() on a server with no onLogLevelSet, set logging: true — it declares the capability on both eras (initialize on legacy, server/discover on modern) and is what allows a level to come into force. Nothing can detect statically that a handler logs, so this is the explicit switch, and without it ctx.log() is a silent no-op.

h3-mcp  MCP servers, built on H3.