Skip to content

Commit 92e747c

Browse files
MCP-3 Support logging from the MCP server
1 parent 7e2bb47 commit 92e747c

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

src/main/java/org/sonar/mcp/SonarMcpServer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public void start() {
7171
.capabilities(McpSchema.ServerCapabilities.builder().tools(true).logging().build())
7272
.tools(supportedTools.stream().map(this::toSpec).toArray(McpServerFeatures.SyncToolSpecification[]::new))
7373
.build();
74-
74+
LOG.setOutput(syncServer);
7575
Runtime.getRuntime().addShutdownHook(new Thread(() -> shutdown(syncServer, backendService)));
7676
}
7777

@@ -104,6 +104,7 @@ private static void shutdown(McpSyncServer syncServer, BackendService backendSer
104104
} catch (Exception e) {
105105
LOG.error("Error shutting down MCP backend", e);
106106
}
107+
McpLogger.getInstance().setOutput(null);
107108
}
108109

109110
}

src/main/java/org/sonar/mcp/log/McpLogger.java

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
*/
2020
package org.sonar.mcp.log;
2121

22+
import io.modelcontextprotocol.server.McpSyncServer;
23+
import io.modelcontextprotocol.spec.McpSchema;
24+
import jakarta.annotation.Nullable;
25+
import java.io.PrintWriter;
26+
import java.io.StringWriter;
2227
import org.sonarsource.sonarlint.core.rpc.protocol.client.log.LogLevel;
2328
import org.sonarsource.sonarlint.core.rpc.protocol.client.log.LogParams;
2429

@@ -29,6 +34,12 @@ public static McpLogger getInstance() {
2934
return INSTANCE;
3035
}
3136

37+
private McpSyncServer syncServer;
38+
39+
public void setOutput(@Nullable McpSyncServer syncServer) {
40+
this.syncServer = syncServer;
41+
}
42+
3243
public void log(LogParams params) {
3344
var stackTrace = params.getStackTrace();
3445
if (stackTrace != null) {
@@ -42,11 +53,33 @@ public void info(String message) {
4253

4354
public void error(String message, Throwable throwable) {
4455
log(message, LogLevel.ERROR);
45-
throwable.printStackTrace();
56+
log(stackTraceToString(throwable), LogLevel.ERROR);
57+
}
58+
59+
private void log(String message, LogLevel level) {
60+
if (syncServer != null) {
61+
// We rely on a deprecated API for now, I opened a discussion in https://github.com/modelcontextprotocol/java-sdk/issues/131
62+
try {
63+
syncServer.loggingNotification(new McpSchema.LoggingMessageNotification(toMcpLevel(level), "sonar-mcp-server", message));
64+
} catch (Exception e) {
65+
// we still print on stdout; some MCP clients print non-JSON message as an error, which is better than nothing
66+
e.printStackTrace();
67+
}
68+
}
69+
}
70+
71+
private static McpSchema.LoggingLevel toMcpLevel(LogLevel level) {
72+
return switch (level) {
73+
case ERROR -> McpSchema.LoggingLevel.ERROR;
74+
case WARN -> McpSchema.LoggingLevel.WARNING;
75+
case INFO -> McpSchema.LoggingLevel.INFO;
76+
case DEBUG, TRACE -> McpSchema.LoggingLevel.DEBUG;
77+
};
4678
}
4779

48-
private static void log(String message, LogLevel level) {
49-
// will be properly implemented in SLCORE-1345
50-
System.out.println("[" + level.name() + "] " + message);
80+
static String stackTraceToString(Throwable t) {
81+
var stringWriter = new StringWriter();
82+
t.printStackTrace(new PrintWriter(stringWriter));
83+
return stringWriter.toString();
5184
}
5285
}

0 commit comments

Comments
 (0)