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.
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.