Class McpProtocolLog

java.lang.Object
com.mcpdbwizard.pub.McpProtocolLog

public final class McpProtocolLog extends Object
The text of one MCP notifications/message — a log line sent to the CLIENT over the protocol, not to the operator.

Why this exists at all, given the feature is deprecated

MCP's in-protocol logging utility is deprecated as of protocol revision 2026-07-28 (SEP-2577), and a new implementation would normally decline to adopt it. What forces the issue is that declining is not available: both McpAsyncServer constructors in SDK 2.0.0 run features.serverCapabilities().mutate().logging().build() unconditionally, so whatever the generated server passes to .capabilities(...) is overwritten and every server advertises logging whether or not it implements it. Verified in the bytecode of both constructors.

So the choice is not "adopt or abstain" but "advertise and implement" or "advertise and do nothing". The second leaves an always-empty stream behind a capability a client is entitled to act on, which is worse than either honest position. This is the cheap half of making the wire true.

Kept free of the MCP SDK, deliberately

This class handles only text: String/Map/long in, String out. Nothing in com.mcpdbwizard.pub may reference the MCP SDK — pub ships with every generated DAO layer, and a DAO layer must not drag an MCP dependency behind it. The SDK types (LoggingMessageNotification, LoggingLevel) appear at exactly one emitted call site in the generated server.

That split is also the deprecation hedge. When the SDK eventually removes those types, the damage is one emitted site behind a generator edit, and no customer's pub jar names the removed classes at all.

Level and volume

These are sent at DEBUG. A session's threshold defaults to INFO and the SDK drops anything below it before it reaches the wire, so a client that never calls logging/setLevel receives nothing — no added traffic and no tokens spent. That is what makes sending them unconditionally affordable, and unconditional is what makes it honest: the capability is advertised for every config, so a flag would leave the mismatch in place for every config that did not set it. Copyright 2003-2026 ATB Consultancy Services Ltd (formerly Orinda Software Ltd, Dublin, Ireland)

  • Method Details

    • logger

      public static String logger(String theServerClassName)
      The logger name carried on each notification. The MCP spec leaves this free-form; the server class is what a client would need in order to tell two servers apart.
    • line

      public static String line(String theToolName, Map<String,Object> theArguments, String theOutcome, long theMilliseconds)
      The message text: which tool ran, how it ended, how long it took, and which arguments it was given BY NAME.
      ob_gen_pkg_greet outcome=ok ms=12 args=[p_name]

      Values are omitted for the same reason McpCallRecord omits them — they were chosen by a model and can carry anything that was put in front of it. The rule is weaker here, since this notification goes back to the caller that supplied those values, but one rule for both records is worth more than the marginal difference: log frames do not always end up in the same place the result does.

      Parameters:
      theToolName - the MCP tool that was invoked
      theArguments - the call's arguments; only the keys are used, and null is fine
      theOutcome - one of McpCallRecord's OUTCOME_ constants
      theMilliseconds - wall-clock duration of the call