Skip to content

Commit 919e838

Browse files
Copilotstephentoub
andauthored
Register ping handler in McpSessionHandler to support server-initiated pings (#1391)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> Co-authored-by: Stephen Toub <stoub@microsoft.com>
1 parent 1108117 commit 919e838

File tree

3 files changed

+20
-9
lines changed

3 files changed

+20
-9
lines changed

src/ModelContextProtocol.Core/McpSessionHandler.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ public McpSessionHandler(
132132
_incomingMessageFilter = incomingMessageFilter ?? (next => next);
133133
_outgoingMessageFilter = outgoingMessageFilter ?? (next => next);
134134
_logger = logger;
135+
136+
// Per the MCP spec, ping may be initiated by either party and must always be handled.
137+
_requestHandlers.Set(
138+
RequestMethods.Ping,
139+
(request, _, cancellationToken) => new ValueTask<PingResult>(new PingResult()),
140+
McpJsonUtilities.JsonContext.Default.JsonNode,
141+
McpJsonUtilities.JsonContext.Default.PingResult);
142+
135143
LogSessionCreated(EndpointName, _sessionId, _transportKind);
136144
}
137145

src/ModelContextProtocol.Core/Server/McpServerImpl.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ public McpServerImpl(ITransport transport, McpServerOptions options, ILoggerFact
9191
ConfigureLogging(options);
9292
ConfigureCompletion(options);
9393
ConfigureExperimental(options);
94-
ConfigurePing();
9594

9695
// Register any notification handlers that were provided.
9796
if (options.Handlers.NotificationHandlers is { } notificationHandlers)
@@ -204,14 +203,6 @@ public override async ValueTask DisposeAsync()
204203
await _sessionHandler.DisposeAsync().ConfigureAwait(false);
205204
}
206205

207-
private void ConfigurePing()
208-
{
209-
SetHandler(RequestMethods.Ping,
210-
async (request, _) => new PingResult(),
211-
McpJsonUtilities.JsonContext.Default.JsonNode,
212-
McpJsonUtilities.JsonContext.Default.PingResult);
213-
}
214-
215206
private void ConfigureInitialize(McpServerOptions options)
216207
{
217208
_requestHandlers.Set(RequestMethods.Initialize,

tests/ModelContextProtocol.Tests/Client/McpClientTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,4 +782,16 @@ public async Task SetLoggingLevelAsync_WithRequestParams_NullThrows()
782782
await Assert.ThrowsAsync<ArgumentNullException>("requestParams",
783783
() => client.SetLoggingLevelAsync((SetLevelRequestParams)null!, TestContext.Current.CancellationToken));
784784
}
785+
786+
[Fact]
787+
public async Task ServerCanPingClient()
788+
{
789+
await using McpClient client = await CreateMcpClientForServer();
790+
791+
var pingRequest = new JsonRpcRequest { Method = RequestMethods.Ping };
792+
var response = await Server.SendRequestAsync(pingRequest, TestContext.Current.CancellationToken);
793+
794+
Assert.NotNull(response);
795+
Assert.NotNull(response.Result);
796+
}
785797
}

0 commit comments

Comments
 (0)