Skip to content

logging/setLevel accepts invalid LoggingLevel values #1070

Description

@cclabadmin

Describe the bug

The logging/setLevel handler accepts level values that are not defined by the LoggingLevel enum. In both tested SDK versions, the server stores the invalid value and returns a successful empty result. When the stored value is used in severity comparisons, unknown levels map to debug.

The 2025-11-25 schema defines LoggingLevel as a closed enum:

"LoggingLevel": {
  "enum": ["alert", "critical", "debug", "emergency", "error", "info", "notice", "warning"],
  "type": "string"
}

And SetLevelRequestParams.level is required and typed as LoggingLevel.

Environment tested:

  • Stable release: v1.6.1 (d454bba)
  • Prerelease: v1.7.0-pre.2 (b426fbf)
  • Server used: conformance/everything-server
  • Transports: stdio, stateful/stateless HTTP (all reproduce)

To Reproduce

Steps to reproduce the behavior:

  1. Start the Go SDK server.
  2. Initialize a session using protocol version 2025-11-25.
  3. Send a logging/setLevel request with an invalid level value:
{"jsonrpc":"2.0","id":1001,"method":"logging/setLevel","params":{"level":"not_a_valid_level"}}
  1. Observe that the server returns a successful result.

Expected behavior

The server should reject the request with -32602 Invalid params, because "not_a_valid_level" is not one of the eight LoggingLevel enum values.

Logs

The server accepts the invalid level and returns {"jsonrpc":"2.0","id":1001,"result":{}}.

This behavior reproduces in both tested SDK versions across all three transports.

Additional context

In mcp/server.go, setLevel stores params.Level unconditionally:

func (ss *ServerSession) setLevel(_ context.Context, params *SetLoggingLevelParams) (*emptyResult, error) {
    ss.updateState(func(state *ServerSessionState) {
        state.LogLevel = params.Level
    })
    ss.server.opts.Logger.Info("client log level set", "level", params.Level)
    return &emptyResult{}, nil
}

LoggingLevel is type LoggingLevel string in mcp/protocol.go, so Go's type system does not enforce the enum constraint.

In mcp/logging.go, mcpLevelToSlog defaults unknown levels to LevelDebug:

func mcpLevelToSlog(ll LoggingLevel) slog.Level {
    if sl, ok := mcpToSlog[ll]; ok {
        return sl
    }
    return LevelDebug
}

As a result, an invalid level is treated as the debug threshold during severity comparisons rather than being rejected by logging/setLevel.

The logging feature is marked deprecated (SEP-2577), but it remains functional during the deprecation window.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions