001/* 002 * Copyright 2022-2026 Revetware LLC. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.soklet; 018 019import org.jspecify.annotations.NonNull; 020 021import javax.annotation.concurrent.ThreadSafe; 022import java.net.InetSocketAddress; 023import java.util.Optional; 024 025/** 026 * An immutable point-in-time snapshot of MCP server diagnostics. 027 * <p> 028 * A retained snapshot never changes. Obtain a new snapshot to observe a later 029 * lifecycle state. 030 * <p> 031 * Lifecycle, handler-capacity, and stream values are captured together at one 032 * runtime linearization point. Protection and trace-correlation values are 033 * captured together at a separate security-control linearization point. No 034 * invariant spans those independently mutable domains. 035 * 036 * @author <a href="https://www.revetkn.com">Mark Allen</a> 037 */ 038@ThreadSafe 039public interface McpServerDiagnostics { 040 /** 041 * The lifecycle status captured by this snapshot. 042 * 043 * @return the server status 044 */ 045 @NonNull 046 McpServerStatus getStatus(); 047 048 /** 049 * The effective bound address captured by this snapshot. 050 * <p> 051 * The address is empty until binding succeeds and includes the 052 * operating-system-assigned port when ephemeral port {@code 0} was 053 * configured. Once published, the effective address remains available as 054 * historical evidence in later shutdown and terminal snapshots. 055 * 056 * @return the effective or historically retained bound address, or empty when 057 * this server never bound 058 */ 059 @NonNull 060 Optional<@NonNull InetSocketAddress> getBoundAddress(); 061 062 /** 063 * The configured maximum number of application request handlers that may 064 * execute concurrently. 065 * <p> 066 * This value is stable across the owner lifecycle. 067 * 068 * @return the configured request-handler concurrency 069 */ 070 @NonNull 071 Integer getRequestHandlerConcurrency(); 072 073 /** 074 * The configured maximum number of admitted application requests that may 075 * wait for a request-handler execution slot. 076 * <p> 077 * This value is stable across the owner lifecycle. 078 * 079 * @return the configured request-handler queue capacity 080 */ 081 @NonNull 082 Integer getRequestHandlerQueueCapacity(); 083 084 /** 085 * The number of application request handlers occupying execution slots in 086 * this snapshot. 087 * <p> 088 * The value includes residual handlers that continue running after server 089 * stop and is between zero and {@link #getRequestHandlerConcurrency()}. 090 * 091 * @return the active handler-execution count 092 */ 093 @NonNull 094 Integer getActiveHandlerExecutions(); 095 096 /** 097 * The number of admitted application requests waiting for a request-handler 098 * execution slot in this snapshot. 099 * <p> 100 * The value is zero after a completed server stop transition and is between 101 * zero and {@link #getRequestHandlerQueueCapacity()}. A transient residual 102 * snapshot captured while failure cleanup is draining work may remain nonzero. 103 * 104 * @return the queued-request count 105 */ 106 @NonNull 107 Integer getRequestHandlerQueueDepth(); 108 109 /** 110 * The number of active SSE streams in this snapshot. 111 * <p> 112 * This count includes request-scoped streams, an MCP subscription once its 113 * acknowledgment stream has opened, and configured 2025 session GET bodies, 114 * including those awaiting physical cleanup. Opening a stream does not imply 115 * client receipt. The value is nonnegative and is zero when 116 * {@link #getStatus()} is {@link McpServerStatus#NOT_STARTED} or 117 * {@link McpServerStatus#TERMINATED}. Residual cleanup can keep this count 118 * nonzero after publication of the owner's immutable shutdown result. 119 * 120 * @return the active request-stream count 121 */ 122 @NonNull 123 Integer getActiveRequestStreams(); 124 125 /** 126 * The number of active subscription streams in this snapshot. 127 * <p> 128 * The count includes an MCP subscription once its acknowledgment stream has 129 * opened and configured 2025 session GET bodies, including those awaiting 130 * physical cleanup. Opening a stream does not imply client receipt. This 131 * value is nonnegative, never exceeds {@link #getActiveRequestStreams()}, 132 * and is zero when {@link #getStatus()} is 133 * {@link McpServerStatus#NOT_STARTED} or {@link McpServerStatus#TERMINATED}. 134 * Residual cleanup can keep this count nonzero after publication of the 135 * owner's immutable shutdown result. 136 * 137 * @return the active subscription count 138 */ 139 @NonNull 140 Integer getActiveSubscriptions(); 141 142 /** 143 * The effective framework request-state protection mode in this snapshot. 144 * <p> 145 * This value is fixed when the server is built and remains stable across 146 * the one-shot owner lifecycle. 147 * 148 * @return the effective protection mode 149 */ 150 @NonNull 151 McpProtectionMode getProtectionMode(); 152 153 /** 154 * Whether an application-owned request-state protector is configured in this 155 * snapshot. 156 * <p> 157 * This value is {@code true} exactly when {@link #getProtectionMode()} is 158 * {@link McpProtectionMode#CUSTOM_PROTECTOR}. It reports provider selection 159 * without exposing the protector instance or its configuration. It does not 160 * report whether an operation declares 161 * {@link McpRequestStateMode#APPLICATION_PROTECTED}; it reports only custom- 162 * protector selection for canonical 163 * {@link McpRequestStateMode#FRAMEWORK_PROTECTED} state. 164 * 165 * @return whether a custom application request-state protector is configured 166 */ 167 @NonNull 168 Boolean isApplicationRequestStateProtectorConfigured(); 169 170 /** 171 * The secret-free fingerprint of the complete live production protection key 172 * ring in this snapshot. 173 * <p> 174 * The fingerprint is present exactly when {@link #getProtectionMode()} is 175 * {@link McpProtectionMode#PRODUCTION_KEYRING}. Successful live ring 176 * mutations are reflected only in subsequently obtained snapshots. The value 177 * excludes trace-correlation configuration, request-state epochs, and cursors, 178 * and exposes neither raw keys nor per-key fingerprint tags. It is operational 179 * deployment-comparison metadata, not an authentication input. 180 * 181 * @return the live production keyring fingerprint, or the empty optional 182 */ 183 @NonNull 184 Optional<@NonNull McpProtectionKeyringFingerprint> 185 getProtectionKeyringFingerprint(); 186 187 /** 188 * The secret-free fingerprint of the active trace-correlation configuration 189 * in this snapshot. 190 * <p> 191 * The fingerprint is present exactly when trace correlation was enabled at 192 * server construction. Successful trace-key rotations are reflected only in 193 * subsequently obtained snapshots. This value is independent of the request- 194 * state protection mode, exposes no raw key material, and is operational 195 * deployment-comparison metadata rather than a token-derivation or 196 * authentication input. 197 * 198 * @return the active trace-correlation configuration fingerprint, or the empty 199 * optional when trace correlation is disabled 200 */ 201 @NonNull 202 Optional<@NonNull McpTraceCorrelationFingerprint> 203 getTraceCorrelationFingerprint(); 204}