In MCP, what does the _meta key io.modelcontextprotocol/logLevel control?
answer
- Verbosity per request, not per connection
- No key, no log notifications at all
- Replaced a removed setter method
- Rides on the originating request's stream
- Deprecated: stderr on stdio, OpenTelemetry beyond
basics
~10 sIt sets the logging verbosity a server may use while handling that one request. Without the key, a server MUST NOT emit notifications/message at all. It replaced logging/setLevel, which MCP revision 2026-07-28 removed.
solid answer
~40 sIn revision 2026-07-28 logging verbosity is a per-request setting, not connection state. A client that wants log notifications puts `io.modelcontextprotocol/logLevel` in that request's `params._meta`; the key is optional, and its absence is meaningful — without it the server MUST NOT emit `notifications/message` for that request. This replaced `logging/setLevel`, which the same revision removed along with everything else that assumed a connection could hold negotiated state. The notifications themselves are request-scoped: they flow on the originating request's own response stream rather than on a subscription stream. Worth knowing too that the whole Logging feature was deprecated in 2026-07-28, with the migration guidance being to write to `stderr` on stdio and to use OpenTelemetry for real observability, so new implementations should not build on it.
go deeper
Remember that log verbosity is set per request through a _meta key, and that omitting it means the server sends no log notifications at all for that call.
Explain why it moved out of a connection-level setter into per-request metadata, and that absence is a prohibition rather than a default level.
Add the operational judgment: the feature is deprecated with at least twelve months of life left, and real diagnostics belong on stderr for stdio and in OpenTelemetry beyond it.
Own the observability position — in-band protocol logs reach one client and only cover opted-in requests, so argue for standard telemetry as the system of record and treat protocol logging as a compatibility surface.
## The key `io.modelcontextprotocol/logLevel` is an optional entry in a request's `params._meta`. It tells the server the verbosity at which the client is willing to receive log notifications while that request is handled. The interesting part is the default. The key is optional, but leaving it out is not "use a sensible default level" — it is an instruction. Without it, a server **MUST NOT** emit `notifications/message` for that request. Logging is opt-in per call, and silence is the correct behaviour for a client that never asked. ## What it replaced, and why Before revision 2026-07-28, a client called `logging/setLevel` once and the server remembered the choice for the connection. That is a textbook piece of negotiated per-connection state, and 2026-07-28 removed it along with the handshake, protocol-level sessions and the rest of the machinery that assumed a connection was a conversation. With statelessness as the organising principle, verbosity had nowhere to live but the request, so it moved into `_meta` beside the protocol version and the capability object. The same reasoning explains the strict default. A stateless server has no memory of a client having asked for logs earlier, so an implicit level would mean every server chattering at every client that never opted in. Making absence mean silence keeps the stateless model honest. ## Where the notifications go Log notifications are request-scoped. `notifications/message` travels on the originating request's own response stream — the same channel carrying that request's progress notifications and its eventual result — rather than on a `subscriptions/listen` stream, which exists for opted-in change notifications about the server's tool, prompt and resource sets. That placement follows naturally from the level being a per-request setting: the logs belong to the call that asked for them. ## Deprecated, not just relocated There is a second half to the story that a candidate should volunteer. The Logging feature as a whole was **deprecated** in revision 2026-07-28. Under MCP's deprecation policy a deprecated feature remains in the specification for at least twelve months, new implementations SHOULD NOT adopt it, and the earliest it can be removed is the first revision released on or after 2027-07-28. So it still works, it is still specified, and building something new on it is discouraged. The migration guidance is deliberately unglamorous: - On stdio, **log to `stderr`**. That channel already exists in the transport, is not part of the JSON-RPC stream, and a client SHOULD NOT read output on it as an error signal — it is for diagnostics. - For real observability, use **OpenTelemetry**. This aligns with the tracing keys the protocol already reserves in `_meta`: `traceparent`, `tracestate` and `baggage`, which are the W3C Trace Context exceptions to the usual prefixed-key naming rule. The reasoning is that in-band protocol logging was never a good observability story. It only reaches one client, it only covers requests that opted in, it cannot describe anything happening outside a request, and it duplicates infrastructure every operator already runs. ## How to handle it in practice If you maintain a server that still supports logging, read the key from each request's `_meta`, apply it to that request only, and emit nothing when it is absent. Do not carry a level forward from a previous request — that would be exactly the prior-request inference the revision forbids. If you are writing a server today, the pragmatic path is to send diagnostics to `stderr` on stdio, instrument with OpenTelemetry for anything you actually intend to operate on, and treat protocol logging as a compatibility surface rather than a foundation. ## Why interviewers ask it It is a small, precise probe for whether a candidate knows the current revision or is reciting the handshake era. Naming `logging/setLevel` as the current mechanism dates an answer immediately. A strong answer gives the key, states that absence means silence rather than a default level, and adds that the feature is on a deprecation clock with `stderr` and OpenTelemetry as the destinations.
- What does a server do when a request's _meta carries no logLevel key?It emits no `notifications/message` for that request. Absence is not a request for a default level — the specification states the server MUST NOT emit log notifications without the key. That strictness is what keeps a stateless server from having to remember whether a client ever opted in.
- Where do those log notifications travel — the listen stream or the request's own stream?The originating request's own response stream, alongside that request's progress notifications and its result. A `subscriptions/listen` stream carries opted-in change notifications about the server's tool, prompt and resource sets; request-scoped notifications never move onto it.
- Given that Logging is deprecated, what should a new MCP server do instead?Write diagnostics to `stderr` on stdio — a channel outside the JSON-RPC stream that a client should not read as an error signal — and use OpenTelemetry for observability, which fits the `traceparent`, `tracestate` and `baggage` keys the protocol already reserves in `_meta`. Deprecated features stay specified at least twelve months, but new work should not build on them.
saying these in an interview costs you the question
- Says logging/setLevel is how you set the level today
- Assumes an absent key means a default info level
- Carries a level forward from an earlier request
- Thinks log notifications arrive on the subscription stream
- Unaware the Logging feature is deprecated