-
Notifications
You must be signed in to change notification settings - Fork 643
Description
Describe the bug
The documentation claims "Incoming ping requests from either side are responded to automatically.". This is correct for Client->Server pings, but when a Server sends a ping to a Client, it will return a Method 'ping' is not available. (-32601) .
For the server side, in McpServerImpl.cs, the constructor explicitly calls ConfigurePing() at line ~94, which registers a handler. This doesn't happen for in McpClientImpl.cs. In McpClientImpl.cs, the RegisterHandlers() method (lines ~72-243) registers handlers for:
sampling/createMessageroots/listelicitation/createtasks/* methods
There is noConfigurePing()call, and no ping handler is registered for the client.
To Reproduce
Steps to reproduce the behavior:
The following code snippet is a fully MRE that shows that Client->Server works fine, but Server->Clients will throw.
// Minimal repro: Server-to-Client ping returns -32601 MethodNotFound
//
// Prerequisites:
// dotnet new web -n PingRepro
// cd PingRepro
// dotnet add package ModelContextProtocol.AspNetCore --version 1.0.0
//
// Replace the generated Program.cs with this file, then: dotnet run
using Microsoft.Extensions.Logging;
using ModelContextProtocol;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
using System.Text.Json;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Debug);
builder.Logging.AddConsole();
// ──────────────────────────────────────────────
// 1. Configure the MCP Server
// ──────────────────────────────────────────────
builder.Services.AddMcpServer(options =>
{
options.ServerInfo = new() { Name = "PingRepro-Server", Version = "1.0.0" };
options.Capabilities = new ServerCapabilities { Tools = new() };
options.Handlers = new()
{
ListToolsHandler = (_, _) => ValueTask.FromResult(new ListToolsResult
{
Tools =
[
new Tool
{
Name = "pingClient",
Description = "Pings the client from the server side and returns the result.",
InputSchema = JsonElement.Parse("""{ "type": "object" }"""),
}
]
}),
CallToolHandler = async (request, cancellationToken) =>
{
if (request.Params?.Name == "pingClient")
{
var server = request.Server;
Console.WriteLine("[SERVER] Tool 'pingClient' invoked — sending ping request back to the client...");
try
{
// Use the public generic SendRequestAsync on McpSession (base of McpServer)
// to send a "ping" JSON-RPC request to the client.
var result = await server.SendRequestAsync<PingRequestParams, PingResult>(
RequestMethods.Ping,
new PingRequestParams(),
cancellationToken: cancellationToken);
Console.WriteLine("[SERVER] Ping response received from client — success!");
return new CallToolResult
{
Content = [new TextContentBlock { Text = "Client responded to ping successfully." }]
};
}
catch (McpException ex)
{
Console.WriteLine($"[SERVER] Ping to client FAILED: {ex.Message}");
return new CallToolResult
{
IsError = true,
Content = [new TextContentBlock { Text = $"Ping failed: {ex.Message}" }]
};
}
}
throw new McpProtocolException($"Unknown tool: '{request.Params?.Name}'", McpErrorCode.InvalidParams);
},
};
}).WithHttpTransport();
var app = builder.Build();
app.MapMcp();
// Start the server in the background
await app.StartAsync();
var serverUrl = app.Urls.First();
Console.WriteLine($"[MAIN] Server started at {serverUrl}");
// ──────────────────────────────────────────────
// 2. Create an MCP Client and connect
// ──────────────────────────────────────────────
using var loggerFactory = LoggerFactory.Create(b =>
{
b.SetMinimumLevel(LogLevel.Debug);
b.AddConsole();
});
var transportOptions = new HttpClientTransportOptions
{
Endpoint = new Uri(serverUrl),
TransportMode = HttpTransportMode.StreamableHttp,
Name = "PingRepro-Client",
};
Console.WriteLine("[CLIENT] Connecting to server...");
await using var client = await McpClient.CreateAsync(
new HttpClientTransport(transportOptions, loggerFactory: loggerFactory),
new McpClientOptions
{
ClientInfo = new() { Name = "PingRepro-Client", Version = "1.0.0" },
},
loggerFactory);
Console.WriteLine($"[CLIENT] Connected. Session ID: {client.SessionId}");
// ──────────────────────────────────────────────
// 3. Client → Server: normal ping (should work)
// ──────────────────────────────────────────────
Console.WriteLine();
Console.WriteLine("=== Test 1: Client pings Server (should succeed) ===");
try
{
await client.PingAsync();
Console.WriteLine("[CLIENT] >>> Client-to-Server ping SUCCEEDED.");
}
catch (Exception ex)
{
Console.WriteLine($"[CLIENT] >>> Client-to-Server ping FAILED: {ex.Message}");
}
// ──────────────────────────────────────────────
// 4. Client calls "pingClient" tool, which makes
// the server send a ping back to the client.
// This is where the -32601 error surfaces.
// ──────────────────────────────────────────────
Console.WriteLine();
Console.WriteLine("=== Test 2: Server pings Client (should fail with -32601) ===");
try
{
var result = await client.CallToolAsync("pingClient");
var text = result.Content.OfType<TextContentBlock>().FirstOrDefault()?.Text;
Console.WriteLine($"[CLIENT] >>> Tool result (IsError={result.IsError}): {text}");
}
catch (Exception ex)
{
Console.WriteLine($"[CLIENT] >>> CallToolAsync threw: {ex.Message}");
}
// ──────────────────────────────────────────────
// Cleanup
// ──────────────────────────────────────────────
Console.WriteLine();
Console.WriteLine("[MAIN] Done. Press Enter to exit.");
Console.ReadLine();
await app.StopAsync();Expected behavior
My McpClient instance to responds according to spec.
Logs
The logs from the MRE above:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5098
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: C:\Users\ROB7609\Development\mcp-csharp-mre-ping
[MAIN] Server started at http://localhost:5098
[CLIENT] Connecting to server...
dbug: ModelContextProtocol.Client.McpClient[1344454274]
PingRepro-Client sending method 'initialize' request.
info: ModelContextProtocol.Server.McpServer[570385771]
Server (PingRepro-Server 1.0.0) method 'initialize' request handler called.
dbug: ModelContextProtocol.Client.StreamableHttpClientSessionTransport[1000831420]
PingRepro-Client transport received message with ID '1'.
dbug: ModelContextProtocol.Client.McpClient[330297028]
PingRepro-Client read JsonRpcResponse message from channel.
info: ModelContextProtocol.Server.McpServer[1867955179]
Server (PingRepro-Server 1.0.0), Client (PingRepro-Client 1.0.0) method 'initialize' request handler completed in 8.2329ms.
dbug: ModelContextProtocol.Client.McpClient[2125972309]
PingRepro-Client waiting for response to request '1' for method 'initialize'.
dbug: ModelContextProtocol.Client.McpClient[638581630]
PingRepro-Client Request response received for method initialize
info: ModelContextProtocol.Client.McpClient[1434756563]
Client (PingRepro-Client 1.0.0) client received server '{"name":"PingRepro-Server","version":"1.0.0"}' capabilities: '{"logging":{},"tools":{}}'.
dbug: ModelContextProtocol.Client.McpClient[1374391956]
PingRepro-Client sending message.
info: ModelContextProtocol.Client.McpClient[1017245113]
Client (PingRepro-Client 1.0.0) client created and connected.
[CLIENT] Connected. Session ID: W5g_uYj0DIeCdU024vLVjA
=== Test 1: Client pings Server (should succeed) ===
dbug: ModelContextProtocol.Client.McpClient[1344454274]
PingRepro-Client sending method 'ping' request.
info: ModelContextProtocol.Server.McpServer[570385771]
Server (PingRepro-Server 1.0.0), Client (PingRepro-Client 1.0.0) method 'ping' request handler called.
info: ModelContextProtocol.Server.McpServer[1867955179]
Server (PingRepro-Server 1.0.0), Client (PingRepro-Client 1.0.0) method 'ping' request handler completed in 2.554ms.
dbug: ModelContextProtocol.Client.StreamableHttpClientSessionTransport[1000831420]
PingRepro-Client transport received message with ID '2'.
dbug: ModelContextProtocol.Client.McpClient[330297028]
PingRepro-Client read JsonRpcResponse message from channel.
dbug: ModelContextProtocol.Client.McpClient[2125972309]
PingRepro-Client waiting for response to request '2' for method 'ping'.
dbug: ModelContextProtocol.Client.McpClient[638581630]
PingRepro-Client Request response received for method ping
[CLIENT] >>> Client-to-Server ping SUCCEEDED.
=== Test 2: Server pings Client (should fail with -32601) ===
dbug: ModelContextProtocol.Client.McpClient[1344454274]
PingRepro-Client sending method 'tools/call' request.
info: ModelContextProtocol.Server.McpServer[570385771]
Server (PingRepro-Server 1.0.0), Client (PingRepro-Client 1.0.0) method 'tools/call' request handler called.
[SERVER] Tool 'pingClient' invoked — sending ping request back to the client...
dbug: ModelContextProtocol.Client.StreamableHttpClientSessionTransport[1000831420]
PingRepro-Client transport received message with ID '1'.
dbug: ModelContextProtocol.Client.McpClient[330297028]
PingRepro-Client read JsonRpcRequest message from channel.
info: ModelContextProtocol.Client.McpClient[570385771]
PingRepro-Client method 'ping' request handler called.
warn: ModelContextProtocol.Client.McpClient[2049951654]
PingRepro-Client received request for method 'ping', but no handler is available.
warn: ModelContextProtocol.Client.McpClient[975074943]
PingRepro-Client method 'ping' request handler failed in 0.508ms.
ModelContextProtocol.McpProtocolException: Method 'ping' is not available.
at ModelContextProtocol.McpSessionHandler.HandleRequestAsync(JsonRpcRequest request, CancellationToken cancellationToken)
at ModelContextProtocol.McpSessionHandler.HandleMessageCoreAsync(JsonRpcMessage message, CancellationToken cancellationToken)
dbug: ModelContextProtocol.Client.McpClient[1374391956]
PingRepro-Client sending message.
warn: ModelContextProtocol.Server.McpServer[145193555]
Server (PingRepro-Server 1.0.0), Client (PingRepro-Client 1.0.0) request failed for method 'ping': Method 'ping' is not available. (-32601).
[SERVER] Ping to client FAILED: Request failed (remote): Method 'ping' is not available.
info: ModelContextProtocol.Server.McpServer[2065726448]
"pingClient" completed. IsError = True.
dbug: ModelContextProtocol.Client.StreamableHttpClientSessionTransport[1000831420]
PingRepro-Client transport received message with ID '3'.
dbug: ModelContextProtocol.Client.McpClient[330297028]
PingRepro-Client read JsonRpcResponse message from channel.
dbug: ModelContextProtocol.Client.McpClient[2125972309]
PingRepro-Client waiting for response to request '3' for method 'tools/call'.
dbug: ModelContextProtocol.Client.McpClient[638581630]
PingRepro-Client Request response received for method tools/call
info: ModelContextProtocol.Server.McpServer[1867955179]
Server (PingRepro-Server 1.0.0), Client (PingRepro-Client 1.0.0) method 'tools/call' request handler completed in 28.8217ms.
[CLIENT] >>> Tool result (IsError=True): Ping failed: Request failed (remote): Method 'ping' is not available.Additional context
Add any other context about the problem here.