Skip to content

Commit 19fa027

Browse files
committed
feat(server): Enhance McpHttpServer with NamedThreadFactory for improved thread management and logging
1 parent 7493fe7 commit 19fa027

File tree

8 files changed

+43
-29
lines changed

8 files changed

+43
-29
lines changed

src/main/java/com/github/codeboyzhou/mcp/declarative/common/NamedThreadFactory.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
import java.util.concurrent.ThreadFactory;
44
import java.util.concurrent.atomic.AtomicInteger;
55
import org.jetbrains.annotations.NotNull;
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
68

79
public final class NamedThreadFactory implements ThreadFactory {
810

11+
private static final Logger log = LoggerFactory.getLogger(NamedThreadFactory.class);
12+
913
private static final AtomicInteger poolNumber = new AtomicInteger(1);
1014

1115
private final AtomicInteger threadNumber = new AtomicInteger(1);
@@ -18,6 +22,13 @@ public NamedThreadFactory(String namePrefix) {
1822

1923
@Override
2024
public Thread newThread(@NotNull Runnable runnable) {
21-
return new Thread(runnable, namePrefix + threadNumber.getAndIncrement());
25+
Thread thread = new Thread(runnable, namePrefix + threadNumber.getAndIncrement());
26+
thread.setUncaughtExceptionHandler(this::handleUncaughtException);
27+
thread.setDaemon(true);
28+
return thread;
29+
}
30+
31+
private void handleUncaughtException(Thread t, Throwable e) {
32+
log.error("Thread {} uncaught exception", t.getName(), e);
2233
}
2334
}

src/main/java/com/github/codeboyzhou/mcp/declarative/server/McpHttpServer.java

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.github.codeboyzhou.mcp.declarative.server;
22

3+
import com.github.codeboyzhou.mcp.declarative.common.NamedThreadFactory;
34
import jakarta.servlet.http.HttpServlet;
45
import java.time.Duration;
6+
import java.util.concurrent.ExecutorService;
7+
import java.util.concurrent.Executors;
58
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
69
import org.eclipse.jetty.ee10.servlet.ServletHolder;
710
import org.eclipse.jetty.server.Server;
@@ -16,10 +19,16 @@ public class McpHttpServer {
1619

1720
private static final String DEFAULT_SERVLET_PATH = "/*";
1821

22+
private final ExecutorService threadPool;
23+
1924
private HttpServlet servlet;
2025

2126
private int port;
2227

28+
public McpHttpServer() {
29+
this.threadPool = Executors.newSingleThreadExecutor(new NamedThreadFactory("mcp-http-server"));
30+
}
31+
2332
public McpHttpServer use(HttpServlet servlet) {
2433
this.servlet = servlet;
2534
return this;
@@ -40,7 +49,7 @@ public void start() {
4049
Server httpserver = new Server(port);
4150
httpserver.setHandler(handler);
4251
httpserver.setStopAtShutdown(true);
43-
httpserver.setStopTimeout(Duration.ofSeconds(5).getSeconds());
52+
httpserver.setStopTimeout(Duration.ofSeconds(5).toMillis());
4453

4554
try {
4655
httpserver.start();
@@ -50,6 +59,10 @@ public void start() {
5059
log.error("Error starting HTTP server on http://127.0.0.1:{}", port, e);
5160
}
5261

62+
threadPool.submit(() -> await(httpserver));
63+
}
64+
65+
private void await(Server httpserver) {
5366
try {
5467
httpserver.join();
5568
} catch (InterruptedException e) {
@@ -58,16 +71,18 @@ public void start() {
5871
}
5972

6073
private void addShutdownHook(Server httpserver) {
61-
Runnable runnable =
62-
() -> {
63-
try {
64-
log.info("Shutting down HTTP server and MCP server");
65-
httpserver.stop();
66-
} catch (Exception e) {
67-
log.error("Error stopping HTTP server and MCP server", e);
68-
}
69-
};
70-
Thread shutdownHook = new Thread(runnable);
71-
Runtime.getRuntime().addShutdownHook(shutdownHook);
74+
Runnable runnable = () -> shutdown(httpserver);
75+
Thread shutdownHookThread = new Thread(runnable);
76+
Runtime.getRuntime().addShutdownHook(shutdownHookThread);
77+
}
78+
79+
private void shutdown(Server httpserver) {
80+
try {
81+
log.info("Shutting down HTTP server and MCP server");
82+
httpserver.stop();
83+
threadPool.shutdown();
84+
} catch (Exception e) {
85+
log.error("Error stopping HTTP server and MCP server", e);
86+
}
7287
}
7388
}

src/main/java/com/github/codeboyzhou/mcp/declarative/server/factory/AbstractMcpServerFactory.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,15 @@
11
package com.github.codeboyzhou.mcp.declarative.server.factory;
22

3-
import com.github.codeboyzhou.mcp.declarative.common.NamedThreadFactory;
43
import com.github.codeboyzhou.mcp.declarative.configuration.McpServerCapabilities;
54
import com.github.codeboyzhou.mcp.declarative.configuration.McpServerChangeNotification;
65
import com.github.codeboyzhou.mcp.declarative.server.McpServerInfo;
76
import com.github.codeboyzhou.mcp.declarative.server.component.McpServerComponentRegister;
87
import io.modelcontextprotocol.server.McpSyncServer;
98
import io.modelcontextprotocol.spec.McpSchema;
10-
import java.util.concurrent.ExecutorService;
11-
import java.util.concurrent.Executors;
129

1310
public abstract class AbstractMcpServerFactory<S extends McpServerInfo>
1411
implements McpServerFactory<S> {
1512

16-
protected final ExecutorService threadPool =
17-
Executors.newSingleThreadExecutor(new NamedThreadFactory("mcp-http-server"));
18-
1913
public void startServer(S serverInfo) {
2014
McpSyncServer server =
2115
sync(serverInfo)

src/main/java/com/github/codeboyzhou/mcp/declarative/server/factory/McpSseServerFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public McpServer.SyncSpecification<?> sync(McpSseServerInfo info) {
2020
.messageEndpoint(info.messageEndpoint())
2121
.build();
2222
McpHttpServer httpserver = new McpHttpServer();
23-
threadPool.execute(() -> httpserver.use(transportProvider).bind(info.port()).start());
23+
httpserver.use(transportProvider).bind(info.port()).start();
2424
return McpServer.sync(transportProvider);
2525
}
2626
}

src/main/java/com/github/codeboyzhou/mcp/declarative/server/factory/McpStreamableServerFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public McpServer.SyncSpecification<?> sync(McpStreamableServerInfo info) {
1717
.keepAliveInterval(info.keepAliveInterval())
1818
.build();
1919
McpHttpServer httpserver = new McpHttpServer();
20-
threadPool.execute(() -> httpserver.use(transportProvider).bind(info.port()).start());
20+
httpserver.use(transportProvider).bind(info.port()).start();
2121
return McpServer.sync(transportProvider);
2222
}
2323
}

src/main/java/com/github/codeboyzhou/mcp/declarative/server/factory/configurable/AbstractConfigurableMcpServerFactory.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
package com.github.codeboyzhou.mcp.declarative.server.factory.configurable;
22

3-
import com.github.codeboyzhou.mcp.declarative.common.NamedThreadFactory;
43
import com.github.codeboyzhou.mcp.declarative.configuration.McpServerCapabilities;
54
import com.github.codeboyzhou.mcp.declarative.configuration.McpServerChangeNotification;
65
import com.github.codeboyzhou.mcp.declarative.configuration.McpServerConfiguration;
76
import com.github.codeboyzhou.mcp.declarative.server.component.McpServerComponentRegister;
87
import io.modelcontextprotocol.server.McpSyncServer;
98
import io.modelcontextprotocol.spec.McpSchema;
109
import java.time.Duration;
11-
import java.util.concurrent.ExecutorService;
12-
import java.util.concurrent.Executors;
1310

1411
public abstract class AbstractConfigurableMcpServerFactory implements ConfigurableMcpServerFactory {
1512

1613
protected final McpServerConfiguration configuration;
1714

18-
protected final ExecutorService threadPool =
19-
Executors.newSingleThreadExecutor(new NamedThreadFactory("configurable-mcp-http-server"));
20-
2115
protected AbstractConfigurableMcpServerFactory(McpServerConfiguration configuration) {
2216
this.configuration = configuration;
2317
}

src/main/java/com/github/codeboyzhou/mcp/declarative/server/factory/configurable/ConfigurableMcpSseServerFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public McpServer.SyncSpecification<?> sync() {
2727
.messageEndpoint(sse.messageEndpoint())
2828
.build();
2929
McpHttpServer httpserver = new McpHttpServer();
30-
threadPool.execute(() -> httpserver.use(transportProvider).bind(sse.port()).start());
30+
httpserver.use(transportProvider).bind(sse.port()).start();
3131
return McpServer.sync(transportProvider);
3232
}
3333
}

src/main/java/com/github/codeboyzhou/mcp/declarative/server/factory/configurable/ConfigurableMcpStreamableServerFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public McpServer.SyncSpecification<?> sync() {
2525
.keepAliveInterval(Duration.ofMillis(streamable.keepAliveInterval()))
2626
.build();
2727
McpHttpServer httpserver = new McpHttpServer();
28-
threadPool.execute(() -> httpserver.use(transportProvider).bind(streamable.port()).start());
28+
httpserver.use(transportProvider).bind(streamable.port()).start();
2929
return McpServer.sync(transportProvider);
3030
}
3131
}

0 commit comments

Comments
 (0)