Skip to content

Commit 1f5f8d6

Browse files
authored
Add configurable strict mode for MCP server initialization (#3)
Adds a Configuration struct to control server behavior around client initialization. When strict mode is enabled, server enforces MCP spec requiring clients to initialize before sending requests. Default mode is more permissive for non-compliant clients.
1 parent 7619e58 commit 1f5f8d6

File tree

1 file changed

+39
-12
lines changed

1 file changed

+39
-12
lines changed

Sources/MCP/Server/Server.swift

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ import class Foundation.JSONEncoder
88

99
/// Model Context Protocol server
1010
public actor Server {
11+
/// The server configuration
12+
public struct Configuration: Hashable, Codable, Sendable {
13+
/// The default configuration.
14+
public static let `default` = Configuration(strict: false)
15+
16+
/// The strict configuration.
17+
public static let strict = Configuration(strict: true)
18+
19+
/// When strict mode is enabled, the server:
20+
/// - Requires clients to send an initialize request before any other requests
21+
/// - Rejects all requests from uninitialized clients with a protocol error
22+
///
23+
/// While the MCP specification requires clients to initialize the connection
24+
/// before sending other requests, some implementations may not follow this.
25+
/// Disabling strict mode allows the server to be more lenient with non-compliant
26+
/// clients, though this may lead to undefined behavior.
27+
public var strict: Bool
28+
}
29+
1130
/// Implementation information
1231
public struct Info: Hashable, Codable, Sendable {
1332
/// The server name
@@ -110,7 +129,9 @@ public actor Server {
110129
/// The server version
111130
public nonisolated var version: String { serverInfo.version }
112131
/// The server capabilities
113-
public var capabilities = Capabilities()
132+
public var capabilities: Capabilities
133+
/// The server configuration
134+
public var configuration: Configuration
114135

115136
/// Request handlers
116137
private var methodHandlers: [String: RequestHandlerBox] = [:]
@@ -133,10 +154,12 @@ public actor Server {
133154
public init(
134155
name: String,
135156
version: String,
136-
capabilities: Server.Capabilities = .init()
157+
capabilities: Server.Capabilities = .init(),
158+
configuration: Configuration = .default
137159
) {
138160
self.serverInfo = Server.Info(name: name, version: version)
139161
self.capabilities = capabilities
162+
self.configuration = configuration
140163
}
141164

142165
/// Start the server
@@ -274,13 +297,15 @@ public actor Server {
274297
"id": "\(request.id)",
275298
])
276299

277-
// The client SHOULD NOT send requests other than pings
278-
// before the server has responded to the initialize request.
279-
switch request.method {
280-
case Initialize.name, Ping.name:
281-
break
282-
default:
283-
try checkInitialized()
300+
if configuration.strict {
301+
// The client SHOULD NOT send requests other than pings
302+
// before the server has responded to the initialize request.
303+
switch request.method {
304+
case Initialize.name, Ping.name:
305+
break
306+
default:
307+
try checkInitialized()
308+
}
284309
}
285310

286311
// Find handler for method name
@@ -308,9 +333,11 @@ public actor Server {
308333
"Processing notification",
309334
metadata: ["method": "\(message.method)"])
310335

311-
// Check initialization state unless this is an initialized notification
312-
if message.method != InitializedNotification.name {
313-
try checkInitialized()
336+
if configuration.strict {
337+
// Check initialization state unless this is an initialized notification
338+
if message.method != InitializedNotification.name {
339+
try checkInitialized()
340+
}
314341
}
315342

316343
// Find notification handlers for this method

0 commit comments

Comments
 (0)