1616
1717package io .helidon .extensions .mcp .server ;
1818
19+ import java .util .Objects ;
20+ import java .util .Optional ;
21+
22+ import io .helidon .webserver .jsonrpc .JsonRpcResponse ;
23+ import io .helidon .webserver .sse .SseSink ;
24+
1925/**
2026 * Support for optional client features like {@link McpProgress} and {@link McpLogger}.
2127 */
2228public final class McpFeatures {
23- private final McpProgress progress ;
24- private final McpLogger logger ;
29+ private final JsonRpcResponse response ;
30+ private final McpSession session ;
31+
32+ private McpProgress progress ;
33+ private McpLogger logger ;
34+ private SseSink sseSink ;
2535
2636 McpFeatures (McpSession session ) {
27- this .logger = new McpLogger (session );
28- this .progress = new McpProgress (session );
37+ Objects .requireNonNull (session , "session is null" );
38+ this .session = session ;
39+ this .response = null ;
40+ }
41+
42+ McpFeatures (JsonRpcResponse response ) {
43+ Objects .requireNonNull (response , "response is null" );
44+ this .response = response ;
45+ this .session = null ;
2946 }
3047
3148 /**
@@ -34,6 +51,14 @@ public final class McpFeatures {
3451 * @return progress
3552 */
3653 public McpProgress progress () {
54+ if (progress == null ) {
55+ if (response != null ) {
56+ sseSink = getOrCreateSseSink ();
57+ progress = new McpProgress (sseSink );
58+ } else if (session != null ) {
59+ progress = new McpProgress (session );
60+ }
61+ }
3762 return progress ;
3863 }
3964
@@ -43,6 +68,33 @@ public McpProgress progress() {
4368 * @return logging
4469 */
4570 public McpLogger logger () {
71+ if (logger == null ) {
72+ if (response != null ) {
73+ sseSink = getOrCreateSseSink ();
74+ logger = new McpLogger (sseSink );
75+ } else if (session != null ) {
76+ logger = new McpLogger (session );
77+ }
78+ }
4679 return logger ;
4780 }
81+
82+ /**
83+ * Get access to underlying SSE sink, if available. This method is package private.
84+ *
85+ * @return optional SSE sink
86+ */
87+ Optional <SseSink > sseSink () {
88+ return Optional .ofNullable (sseSink );
89+ }
90+
91+ /**
92+ * Get or create an SSE sink.
93+ *
94+ * @return the SSE sink
95+ */
96+ private SseSink getOrCreateSseSink () {
97+ Objects .requireNonNull (response , "response is null" );
98+ return sseSink != null ? sseSink : response .sink (SseSink .TYPE );
99+ }
48100}
0 commit comments