From 1b7131069d8f17ff77a7f1752830a52932622dfa Mon Sep 17 00:00:00 2001 From: KSE Date: Mon, 8 Sep 2025 19:16:40 +0300 Subject: [PATCH 1/3] Add missing inputSchema object properties for tools listing. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ac23a4c3..a0e76325 100644 --- a/README.md +++ b/README.md @@ -434,6 +434,7 @@ await server.withMethodHandler(ListTools.self) { _ in name: "weather", description: "Get current weather for a location", inputSchema: .object([ + "type": .string("object"), "properties": .object([ "location": .string("City name or coordinates"), "units": .string("Units of measurement, e.g., metric, imperial") @@ -444,6 +445,7 @@ await server.withMethodHandler(ListTools.self) { _ in name: "calculator", description: "Perform calculations", inputSchema: .object([ + "type": .string("object"), "properties": .object([ "expression": .string("Mathematical expression to evaluate") ]) From 0e2b19828ebb23fe94f7a4c0cb84d07abd9854bf Mon Sep 17 00:00:00 2001 From: KSE Date: Mon, 8 Sep 2025 19:23:09 +0300 Subject: [PATCH 2/3] Fix service: remove unprotocoled shutdown() func, use the designed func to wait for the running server. --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a0e76325..202c9833 100644 --- a/README.md +++ b/README.md @@ -694,13 +694,8 @@ struct MCPService: Service { // Start the server try await server.start(transport: transport) - // Keep running until external cancellation - try await Task.sleep(for: .days(365 * 100)) // Effectively forever - } - - func shutdown() async throws { - // Gracefully shutdown the server - await server.stop() + // Keep running until external cancellation or receiving EOF + await server.waitUntilCompleted() } } ``` From 92b499eb4a29e12965a660f704a3b86a5d45a55f Mon Sep 17 00:00:00 2001 From: KSE Date: Mon, 8 Sep 2025 20:00:17 +0300 Subject: [PATCH 3/3] Make successfully finished mcpService to gracefully shutdown its group. --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 202c9833..e99450eb 100644 --- a/README.md +++ b/README.md @@ -735,17 +735,20 @@ await server.withMethodHandler(CallTool.self) { params in // Create MCP service and other services let transport = StdioTransport(logger: logger) + let mcpService = MCPService(server: server, transport: transport) +// use .gracefullyShutdownGroup instead of the default .cancelGroup, because group cancellation leads to ServiceGroupError.serviceFinishedUnexpectedly when mcpService receives, for example, EOF, which is a normal signal to shutdown +let mcpServiceCfg = ServiceGroupConfiguration.ServiceConfiguration(service: mcpService, successTerminationBehavior: .gracefullyShutdownGroup) + let databaseService = DatabaseService() // Your other services +let databaseServiceCfg = ServiceGroupConfiguration.ServiceConfiguration(service: databaseService) // Create service group with signal handling -let serviceGroup = ServiceGroup( - services: [mcpService, databaseService], - configuration: .init( - gracefulShutdownSignals: [.sigterm, .sigint] - ), - logger: logger -) +let serviceGroupCfg = ServiceGroupConfiguration( + services: [mcpServiceCfg, databaseServiceCfg], + gracefulShutdownSignals: [.sigterm, .sigint], + logger: logger) +let serviceGroup = ServiceGroup(configuration: serviceGroupCfg) // Run the service group - this blocks until shutdown try await serviceGroup.run() @@ -757,8 +760,6 @@ This approach has several benefits: Automatically traps SIGINT, SIGTERM and triggers graceful shutdown - **Graceful shutdown**: Properly shuts down your MCP server and other services -- **Timeout-based shutdown**: - Configurable shutdown timeouts to prevent hanging processes - **Advanced service management**: [`ServiceLifecycle`](https://swiftpackageindex.com/swift-server/swift-service-lifecycle/documentation/servicelifecycle) also supports service dependencies, conditional services,